summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-06-08 16:52:24 +0000
committerChris Lattner <sabre@nondot.org>2010-06-08 16:52:24 +0000
commit30fdc8d841c9d24ac5f3d452b6ece84ee0ac991c (patch)
treef70013106f6a461a14abcd71c65f48a95a2979a6
parent312c4c799da215b337f790fda330f70c4aa757cf (diff)
downloadbcm5719-llvm-30fdc8d841c9d24ac5f3d452b6ece84ee0ac991c.tar.gz
bcm5719-llvm-30fdc8d841c9d24ac5f3d452b6ece84ee0ac991c.zip
Initial checkin of lldb code from internal Apple repo.
llvm-svn: 105619
-rw-r--r--lldb/docs/code-signing.txt47
-rw-r--r--lldb/docs/code_signing.txt47
-rw-r--r--lldb/include/lldb/API/LLDB.h49
-rw-r--r--lldb/include/lldb/API/SBAddress.h75
-rw-r--r--lldb/include/lldb/API/SBBlock.h44
-rw-r--r--lldb/include/lldb/API/SBBreakpoint.h129
-rw-r--r--lldb/include/lldb/API/SBBreakpointLocation.h73
-rw-r--r--lldb/include/lldb/API/SBBroadcaster.h83
-rw-r--r--lldb/include/lldb/API/SBCommandContext.h36
-rw-r--r--lldb/include/lldb/API/SBCommandInterpreter.h105
-rw-r--r--lldb/include/lldb/API/SBCommandReturnObject.h80
-rw-r--r--lldb/include/lldb/API/SBCommunication.h97
-rw-r--r--lldb/include/lldb/API/SBCompileUnit.h75
-rw-r--r--lldb/include/lldb/API/SBDebugger.h148
-rw-r--r--lldb/include/lldb/API/SBDefines.h62
-rw-r--r--lldb/include/lldb/API/SBError.h102
-rw-r--r--lldb/include/lldb/API/SBEvent.h89
-rw-r--r--lldb/include/lldb/API/SBFileSpec.h83
-rw-r--r--lldb/include/lldb/API/SBFrame.h130
-rw-r--r--lldb/include/lldb/API/SBFunction.h55
-rw-r--r--lldb/include/lldb/API/SBHostOS.h54
-rw-r--r--lldb/include/lldb/API/SBInputReader.h100
-rw-r--r--lldb/include/lldb/API/SBInstruction.h57
-rw-r--r--lldb/include/lldb/API/SBInstructionList.h53
-rw-r--r--lldb/include/lldb/API/SBLineEntry.h88
-rw-r--r--lldb/include/lldb/API/SBListener.h119
-rw-r--r--lldb/include/lldb/API/SBModule.h79
-rw-r--r--lldb/include/lldb/API/SBProcess.h195
-rw-r--r--lldb/include/lldb/API/SBSourceManager.h47
-rw-r--r--lldb/include/lldb/API/SBStringList.h72
-rw-r--r--lldb/include/lldb/API/SBSymbol.h55
-rw-r--r--lldb/include/lldb/API/SBSymbolContext.h73
-rw-r--r--lldb/include/lldb/API/SBTarget.h167
-rw-r--r--lldb/include/lldb/API/SBThread.h152
-rw-r--r--lldb/include/lldb/API/SBType.h31
-rw-r--r--lldb/include/lldb/API/SBValue.h126
-rw-r--r--lldb/include/lldb/API/SBValueList.h79
-rw-r--r--lldb/include/lldb/Breakpoint/Breakpoint.h511
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointID.h117
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointIDList.h82
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointList.h177
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointLocation.h354
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h187
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointLocationList.h285
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointOptions.h210
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointResolver.h123
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h68
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h65
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointResolverName.h75
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointSite.h258
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointSiteList.h217
-rw-r--r--lldb/include/lldb/Breakpoint/Stoppoint.h63
-rw-r--r--lldb/include/lldb/Breakpoint/StoppointCallbackContext.h58
-rw-r--r--lldb/include/lldb/Breakpoint/StoppointLocation.h111
-rw-r--r--lldb/include/lldb/Breakpoint/WatchpointLocation.h69
-rw-r--r--lldb/include/lldb/Core/Address.h425
-rw-r--r--lldb/include/lldb/Core/AddressRange.h280
-rw-r--r--lldb/include/lldb/Core/AddressResolver.h90
-rw-r--r--lldb/include/lldb/Core/AddressResolverFileLine.h59
-rw-r--r--lldb/include/lldb/Core/AddressResolverName.h67
-rw-r--r--lldb/include/lldb/Core/ArchSpec.h326
-rw-r--r--lldb/include/lldb/Core/Args.h368
-rw-r--r--lldb/include/lldb/Core/Baton.h62
-rw-r--r--lldb/include/lldb/Core/Broadcaster.h194
-rw-r--r--lldb/include/lldb/Core/ClangForward.h103
-rw-r--r--lldb/include/lldb/Core/Communication.h401
-rw-r--r--lldb/include/lldb/Core/Connection.h176
-rw-r--r--lldb/include/lldb/Core/ConnectionFileDescriptor.h74
-rw-r--r--lldb/include/lldb/Core/ConstString.h396
-rw-r--r--lldb/include/lldb/Core/DataBuffer.h94
-rw-r--r--lldb/include/lldb/Core/DataBufferHeap.h136
-rw-r--r--lldb/include/lldb/Core/DataBufferMemoryMap.h156
-rw-r--r--lldb/include/lldb/Core/DataExtractor.h1124
-rw-r--r--lldb/include/lldb/Core/Debugger.h170
-rw-r--r--lldb/include/lldb/Core/Disassembler.h138
-rw-r--r--lldb/include/lldb/Core/Error.h291
-rw-r--r--lldb/include/lldb/Core/Event.h180
-rw-r--r--lldb/include/lldb/Core/FileSpec.h440
-rw-r--r--lldb/include/lldb/Core/FileSpecList.h196
-rw-r--r--lldb/include/lldb/Core/Flags.h153
-rw-r--r--lldb/include/lldb/Core/IOStreamMacros.h38
-rw-r--r--lldb/include/lldb/Core/InputReader.h114
-rw-r--r--lldb/include/lldb/Core/Language.h149
-rw-r--r--lldb/include/lldb/Core/Listener.h173
-rw-r--r--lldb/include/lldb/Core/Log.h243
-rw-r--r--lldb/include/lldb/Core/Mangled.h485
-rw-r--r--lldb/include/lldb/Core/Module.h597
-rw-r--r--lldb/include/lldb/Core/ModuleChild.h103
-rw-r--r--lldb/include/lldb/Core/ModuleList.h339
-rw-r--r--lldb/include/lldb/Core/Options.h296
-rw-r--r--lldb/include/lldb/Core/PluginInterface.h46
-rw-r--r--lldb/include/lldb/Core/PluginManager.h186
-rw-r--r--lldb/include/lldb/Core/RegularExpression.h166
-rw-r--r--lldb/include/lldb/Core/STLUtils.h104
-rw-r--r--lldb/include/lldb/Core/Scalar.h302
-rw-r--r--lldb/include/lldb/Core/SearchFilter.h326
-rw-r--r--lldb/include/lldb/Core/Section.h231
-rw-r--r--lldb/include/lldb/Core/SourceManager.h120
-rw-r--r--lldb/include/lldb/Core/State.h43
-rw-r--r--lldb/include/lldb/Core/Stream.h599
-rw-r--r--lldb/include/lldb/Core/StreamFile.h76
-rw-r--r--lldb/include/lldb/Core/StreamString.h61
-rw-r--r--lldb/include/lldb/Core/StringList.h74
-rw-r--r--lldb/include/lldb/Core/TTYState.h202
-rw-r--r--lldb/include/lldb/Core/ThreadSafeSTLMap.h170
-rw-r--r--lldb/include/lldb/Core/ThreadSafeValue.h96
-rw-r--r--lldb/include/lldb/Core/Timer.h93
-rw-r--r--lldb/include/lldb/Core/UUID.h80
-rw-r--r--lldb/include/lldb/Core/UniqueCStringMap.h232
-rw-r--r--lldb/include/lldb/Core/UserID.h123
-rw-r--r--lldb/include/lldb/Core/VMRange.h165
-rw-r--r--lldb/include/lldb/Core/Value.h172
-rw-r--r--lldb/include/lldb/Core/ValueObject.h230
-rw-r--r--lldb/include/lldb/Core/ValueObjectChild.h95
-rw-r--r--lldb/include/lldb/Core/ValueObjectList.h74
-rw-r--r--lldb/include/lldb/Core/ValueObjectRegister.h168
-rw-r--r--lldb/include/lldb/Core/ValueObjectVariable.h70
-rw-r--r--lldb/include/lldb/Core/dwarf.h589
-rw-r--r--lldb/include/lldb/Expression/ClangASTSource.h67
-rw-r--r--lldb/include/lldb/Expression/ClangExpression.h124
-rw-r--r--lldb/include/lldb/Expression/ClangExpressionDeclMap.h71
-rw-r--r--lldb/include/lldb/Expression/ClangExpressionVariable.h58
-rw-r--r--lldb/include/lldb/Expression/ClangFunction.h241
-rw-r--r--lldb/include/lldb/Expression/ClangStmtVisitor.h109
-rw-r--r--lldb/include/lldb/Expression/DWARFExpression.h126
-rw-r--r--lldb/include/lldb/Expression/RecordingMemoryManager.h154
-rw-r--r--lldb/include/lldb/Host/Condition.h123
-rw-r--r--lldb/include/lldb/Host/Endian.h19
-rw-r--r--lldb/include/lldb/Host/Host.h281
-rw-r--r--lldb/include/lldb/Host/Mutex.h242
-rw-r--r--lldb/include/lldb/Host/Predicate.h411
-rw-r--r--lldb/include/lldb/Host/Symbols.h37
-rw-r--r--lldb/include/lldb/Host/TimeValue.h90
-rw-r--r--lldb/include/lldb/Host/Types.h98
-rw-r--r--lldb/include/lldb/Interpreter/CommandCompletions.h240
-rw-r--r--lldb/include/lldb/Interpreter/CommandContext.h43
-rw-r--r--lldb/include/lldb/Interpreter/CommandInterpreter.h264
-rw-r--r--lldb/include/lldb/Interpreter/CommandObject.h194
-rw-r--r--lldb/include/lldb/Interpreter/CommandObjectCrossref.h60
-rw-r--r--lldb/include/lldb/Interpreter/CommandObjectMultiword.h73
-rw-r--r--lldb/include/lldb/Interpreter/CommandObjectRegexCommand.h73
-rw-r--r--lldb/include/lldb/Interpreter/CommandReturnObject.h90
-rw-r--r--lldb/include/lldb/Interpreter/ScriptInterpreter.h103
-rw-r--r--lldb/include/lldb/Interpreter/ScriptInterpreterNone.h35
-rw-r--r--lldb/include/lldb/Interpreter/ScriptInterpreterPython.h86
-rw-r--r--lldb/include/lldb/Interpreter/StateVariable.h145
-rw-r--r--lldb/include/lldb/Symbol/Block.h721
-rw-r--r--lldb/include/lldb/Symbol/ClangASTContext.h417
-rw-r--r--lldb/include/lldb/Symbol/CompileUnit.h395
-rw-r--r--lldb/include/lldb/Symbol/DWARFCallFrameInfo.h312
-rw-r--r--lldb/include/lldb/Symbol/Declaration.h204
-rw-r--r--lldb/include/lldb/Symbol/Function.h587
-rw-r--r--lldb/include/lldb/Symbol/LineEntry.h170
-rw-r--r--lldb/include/lldb/Symbol/LineTable.h333
-rw-r--r--lldb/include/lldb/Symbol/ObjectContainer.h232
-rw-r--r--lldb/include/lldb/Symbol/ObjectFile.h309
-rw-r--r--lldb/include/lldb/Symbol/Symbol.h181
-rw-r--r--lldb/include/lldb/Symbol/SymbolContext.h328
-rw-r--r--lldb/include/lldb/Symbol/SymbolContextScope.h79
-rw-r--r--lldb/include/lldb/Symbol/SymbolFile.h95
-rw-r--r--lldb/include/lldb/Symbol/SymbolVendor.h193
-rw-r--r--lldb/include/lldb/Symbol/Symtab.h77
-rw-r--r--lldb/include/lldb/Symbol/Type.h286
-rw-r--r--lldb/include/lldb/Symbol/TypeList.h94
-rw-r--r--lldb/include/lldb/Symbol/Variable.h123
-rw-r--r--lldb/include/lldb/Symbol/VariableList.h74
-rw-r--r--lldb/include/lldb/Target/ABI.h67
-rw-r--r--lldb/include/lldb/Target/DynamicLoader.h154
-rw-r--r--lldb/include/lldb/Target/ExecutionContext.h93
-rw-r--r--lldb/include/lldb/Target/ExecutionContextScope.h71
-rw-r--r--lldb/include/lldb/Target/ObjCObjectPrinter.h49
-rw-r--r--lldb/include/lldb/Target/PathMappingList.h82
-rw-r--r--lldb/include/lldb/Target/Process.h1415
-rw-r--r--lldb/include/lldb/Target/RegisterContext.h172
-rw-r--r--lldb/include/lldb/Target/StackFrame.h126
-rw-r--r--lldb/include/lldb/Target/StackFrameList.h88
-rw-r--r--lldb/include/lldb/Target/StackID.h65
-rw-r--r--lldb/include/lldb/Target/Target.h324
-rw-r--r--lldb/include/lldb/Target/TargetList.h206
-rw-r--r--lldb/include/lldb/Target/Thread.h701
-rw-r--r--lldb/include/lldb/Target/ThreadList.h120
-rw-r--r--lldb/include/lldb/Target/ThreadPlan.h358
-rw-r--r--lldb/include/lldb/Target/ThreadPlanBase.h66
-rw-r--r--lldb/include/lldb/Target/ThreadPlanCallFunction.h96
-rw-r--r--lldb/include/lldb/Target/ThreadPlanContinue.h60
-rw-r--r--lldb/include/lldb/Target/ThreadPlanRunToAddress.h78
-rw-r--r--lldb/include/lldb/Target/ThreadPlanShouldStopHere.h94
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepInRange.h76
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepInstruction.h61
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepOut.h72
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepOverBreakpoint.h55
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepOverRange.h56
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepRange.h74
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepThrough.h58
-rw-r--r--lldb/include/lldb/Target/ThreadPlanStepUntil.h83
-rw-r--r--lldb/include/lldb/Target/UnixSignals.h168
-rw-r--r--lldb/include/lldb/Target/Unwind.h69
-rw-r--r--lldb/include/lldb/lldb-defines.h88
-rw-r--r--lldb/include/lldb/lldb-enumerations.h358
-rw-r--r--lldb/include/lldb/lldb-forward-rtti.h76
-rw-r--r--lldb/include/lldb/lldb-forward.h149
-rw-r--r--lldb/include/lldb/lldb-include.h19
-rw-r--r--lldb/include/lldb/lldb-private-interfaces.h37
-rw-r--r--lldb/include/lldb/lldb-private-log.h83
-rw-r--r--lldb/include/lldb/lldb-private.h77
-rw-r--r--lldb/include/lldb/lldb-types.h168
-rw-r--r--lldb/lldb.runcontext49
-rw-r--r--lldb/lldb.xcodeproj/project.pbxproj3020
-rw-r--r--lldb/lldb.xcworkspace/contents.xcworkspacedata18
-rw-r--r--lldb/resources/LLDB-Info.plist24
-rw-r--r--lldb/resources/lldb-framework-exports3
-rwxr-xr-xlldb/scripts/Python/build-swig-Python.sh127
-rw-r--r--lldb/scripts/Python/edit-swig-python-wrapper-file.py58
-rwxr-xr-xlldb/scripts/Python/finish-swig-Python-LLDB.sh45
-rw-r--r--lldb/scripts/build-llvm.pl409
-rwxr-xr-xlldb/scripts/build-swig-wrapper-classes.sh85
-rwxr-xr-xlldb/scripts/checkpoint-llvm.pl101
-rwxr-xr-xlldb/scripts/finish-swig-wrapper-classes.sh71
-rwxr-xr-xlldb/scripts/install-lldb.sh59
-rw-r--r--lldb/scripts/lldb.swig149
-rwxr-xr-xlldb/scripts/sed-sources252
-rw-r--r--lldb/source/API/SBAddress.cpp118
-rw-r--r--lldb/source/API/SBBlock.cpp47
-rw-r--r--lldb/source/API/SBBreakpoint.cpp404
-rw-r--r--lldb/source/API/SBBreakpointLocation.cpp162
-rw-r--r--lldb/source/API/SBBroadcaster.cpp142
-rw-r--r--lldb/source/API/SBCommandContext.cpp34
-rw-r--r--lldb/source/API/SBCommandInterpreter.cpp193
-rw-r--r--lldb/source/API/SBCommandReturnObject.cpp148
-rw-r--r--lldb/source/API/SBCommunication.cpp194
-rw-r--r--lldb/source/API/SBCompileUnit.cpp120
-rw-r--r--lldb/source/API/SBDebugger.cpp569
-rw-r--r--lldb/source/API/SBError.cpp179
-rw-r--r--lldb/source/API/SBEvent.cpp176
-rw-r--r--lldb/source/API/SBFileSpec.cpp133
-rw-r--r--lldb/source/API/SBFrame.cpp394
-rw-r--r--lldb/source/API/SBFunction.cpp64
-rw-r--r--lldb/source/API/SBHostOS.cpp64
-rw-r--r--lldb/source/API/SBInputReader.cpp169
-rw-r--r--lldb/source/API/SBInstruction.cpp74
-rw-r--r--lldb/source/API/SBInstructionList.cpp53
-rw-r--r--lldb/source/API/SBLineEntry.cpp158
-rw-r--r--lldb/source/API/SBListener.cpp299
-rw-r--r--lldb/source/API/SBModule.cpp107
-rw-r--r--lldb/source/API/SBProcess.cpp604
-rw-r--r--lldb/source/API/SBSourceManager.cpp65
-rw-r--r--lldb/source/API/SBStringList.cpp134
-rw-r--r--lldb/source/API/SBSymbol.cpp64
-rw-r--r--lldb/source/API/SBSymbolContext.cpp133
-rw-r--r--lldb/source/API/SBTarget.cpp553
-rw-r--r--lldb/source/API/SBThread.cpp551
-rw-r--r--lldb/source/API/SBType.cpp23
-rw-r--r--lldb/source/API/SBValue.cpp372
-rw-r--r--lldb/source/API/SBValueList.cpp140
-rw-r--r--lldb/source/Breakpoint/Breakpoint.cpp516
-rw-r--r--lldb/source/Breakpoint/BreakpointID.cpp120
-rw-r--r--lldb/source/Breakpoint/BreakpointIDList.cpp348
-rw-r--r--lldb/source/Breakpoint/BreakpointList.cpp198
-rw-r--r--lldb/source/Breakpoint/BreakpointLocation.cpp389
-rw-r--r--lldb/source/Breakpoint/BreakpointLocationCollection.cpp161
-rw-r--r--lldb/source/Breakpoint/BreakpointLocationList.cpp305
-rw-r--r--lldb/source/Breakpoint/BreakpointOptions.cpp180
-rw-r--r--lldb/source/Breakpoint/BreakpointResolver.cpp60
-rw-r--r--lldb/source/Breakpoint/BreakpointResolverAddress.cpp111
-rw-r--r--lldb/source/Breakpoint/BreakpointResolverFileLine.cpp122
-rw-r--r--lldb/source/Breakpoint/BreakpointResolverName.cpp252
-rw-r--r--lldb/source/Breakpoint/BreakpointSite.cpp221
-rw-r--r--lldb/source/Breakpoint/BreakpointSiteList.cpp229
-rw-r--r--lldb/source/Breakpoint/Stoppoint.cpp46
-rw-r--r--lldb/source/Breakpoint/StoppointCallbackContext.cpp38
-rw-r--r--lldb/source/Breakpoint/StoppointLocation.cpp120
-rw-r--r--lldb/source/Breakpoint/WatchpointLocation.cpp137
-rw-r--r--lldb/source/Commands/CommandObjectAdd.cpp51
-rw-r--r--lldb/source/Commands/CommandObjectAdd.h43
-rw-r--r--lldb/source/Commands/CommandObjectAlias.cpp225
-rw-r--r--lldb/source/Commands/CommandObjectAlias.h43
-rw-r--r--lldb/source/Commands/CommandObjectAppend.cpp95
-rw-r--r--lldb/source/Commands/CommandObjectAppend.h43
-rw-r--r--lldb/source/Commands/CommandObjectApropos.cpp96
-rw-r--r--lldb/source/Commands/CommandObjectApropos.h45
-rw-r--r--lldb/source/Commands/CommandObjectArgs.cpp279
-rw-r--r--lldb/source/Commands/CommandObjectArgs.h76
-rw-r--r--lldb/source/Commands/CommandObjectBreakpoint.cpp953
-rw-r--r--lldb/source/Commands/CommandObjectBreakpoint.h235
-rw-r--r--lldb/source/Commands/CommandObjectBreakpointCommand.cpp695
-rw-r--r--lldb/source/Commands/CommandObjectBreakpointCommand.h169
-rw-r--r--lldb/source/Commands/CommandObjectCall.cpp307
-rw-r--r--lldb/source/Commands/CommandObjectCall.h84
-rw-r--r--lldb/source/Commands/CommandObjectDelete.cpp32
-rw-r--r--lldb/source/Commands/CommandObjectDelete.h37
-rw-r--r--lldb/source/Commands/CommandObjectDisassemble.cpp431
-rw-r--r--lldb/source/Commands/CommandObjectDisassemble.h95
-rw-r--r--lldb/source/Commands/CommandObjectExpression.cpp554
-rw-r--r--lldb/source/Commands/CommandObjectExpression.h105
-rw-r--r--lldb/source/Commands/CommandObjectFile.cpp170
-rw-r--r--lldb/source/Commands/CommandObjectFile.h79
-rw-r--r--lldb/source/Commands/CommandObjectFrame.cpp171
-rw-r--r--lldb/source/Commands/CommandObjectFrame.h40
-rw-r--r--lldb/source/Commands/CommandObjectHelp.cpp266
-rw-r--r--lldb/source/Commands/CommandObjectHelp.h59
-rw-r--r--lldb/source/Commands/CommandObjectImage.cpp1419
-rw-r--r--lldb/source/Commands/CommandObjectImage.h44
-rw-r--r--lldb/source/Commands/CommandObjectInfo.cpp32
-rw-r--r--lldb/source/Commands/CommandObjectInfo.h37
-rw-r--r--lldb/source/Commands/CommandObjectLog.cpp452
-rw-r--r--lldb/source/Commands/CommandObjectLog.h48
-rw-r--r--lldb/source/Commands/CommandObjectMemory.cpp680
-rw-r--r--lldb/source/Commands/CommandObjectMemory.h33
-rw-r--r--lldb/source/Commands/CommandObjectProcess.cpp833
-rw-r--r--lldb/source/Commands/CommandObjectProcess.h37
-rw-r--r--lldb/source/Commands/CommandObjectQuit.cpp48
-rw-r--r--lldb/source/Commands/CommandObjectQuit.h51
-rw-r--r--lldb/source/Commands/CommandObjectRegister.cpp231
-rw-r--r--lldb/source/Commands/CommandObjectRegister.h44
-rw-r--r--lldb/source/Commands/CommandObjectRemove.cpp89
-rw-r--r--lldb/source/Commands/CommandObjectRemove.h44
-rw-r--r--lldb/source/Commands/CommandObjectScript.cpp149
-rw-r--r--lldb/source/Commands/CommandObjectScript.h58
-rw-r--r--lldb/source/Commands/CommandObjectSelect.cpp32
-rw-r--r--lldb/source/Commands/CommandObjectSelect.h37
-rw-r--r--lldb/source/Commands/CommandObjectSet.cpp153
-rw-r--r--lldb/source/Commands/CommandObjectSet.h44
-rw-r--r--lldb/source/Commands/CommandObjectSettings.cpp62
-rw-r--r--lldb/source/Commands/CommandObjectSettings.h44
-rw-r--r--lldb/source/Commands/CommandObjectShow.cpp74
-rw-r--r--lldb/source/Commands/CommandObjectShow.h44
-rw-r--r--lldb/source/Commands/CommandObjectSource.cpp127
-rw-r--r--lldb/source/Commands/CommandObjectSource.h48
-rw-r--r--lldb/source/Commands/CommandObjectSourceFile.cpp206
-rw-r--r--lldb/source/Commands/CommandObjectSourceFile.h80
-rw-r--r--lldb/source/Commands/CommandObjectStatus.cpp97
-rw-r--r--lldb/source/Commands/CommandObjectStatus.h44
-rw-r--r--lldb/source/Commands/CommandObjectSyntax.cpp148
-rw-r--r--lldb/source/Commands/CommandObjectSyntax.h51
-rw-r--r--lldb/source/Commands/CommandObjectTarget.cpp430
-rw-r--r--lldb/source/Commands/CommandObjectTarget.h41
-rw-r--r--lldb/source/Commands/CommandObjectThread.cpp1277
-rw-r--r--lldb/source/Commands/CommandObjectThread.h87
-rw-r--r--lldb/source/Commands/CommandObjectTranslate.cpp75
-rw-r--r--lldb/source/Commands/CommandObjectTranslate.h44
-rw-r--r--lldb/source/Commands/CommandObjectUnalias.cpp87
-rw-r--r--lldb/source/Commands/CommandObjectUnalias.h44
-rw-r--r--lldb/source/Commands/CommandObjectVariable.cpp801
-rw-r--r--lldb/source/Commands/CommandObjectVariable.h43
-rw-r--r--lldb/source/Core/Address.cpp875
-rw-r--r--lldb/source/Core/AddressRange.cpp222
-rw-r--r--lldb/source/Core/AddressResolver.cpp67
-rw-r--r--lldb/source/Core/AddressResolverFileLine.cpp100
-rw-r--r--lldb/source/Core/AddressResolverName.cpp231
-rw-r--r--lldb/source/Core/ArchSpec.cpp1681
-rw-r--r--lldb/source/Core/Args.cpp1179
-rw-r--r--lldb/source/Core/Baton.cpp25
-rw-r--r--lldb/source/Core/Broadcaster.cpp219
-rw-r--r--lldb/source/Core/Communication.cpp363
-rw-r--r--lldb/source/Core/Connection.cpp24
-rw-r--r--lldb/source/Core/ConnectionFileDescriptor.cpp563
-rw-r--r--lldb/source/Core/ConstString.cpp480
-rw-r--r--lldb/source/Core/DataBufferHeap.cpp105
-rw-r--r--lldb/source/Core/DataBufferMemoryMap.cpp214
-rw-r--r--lldb/source/Core/DataExtractor.cpp1517
-rw-r--r--lldb/source/Core/Debugger.cpp434
-rw-r--r--lldb/source/Core/Disassembler.cpp299
-rw-r--r--lldb/source/Core/DynamicLoader.cpp75
-rw-r--r--lldb/source/Core/Error.cpp365
-rw-r--r--lldb/source/Core/Event.cpp241
-rw-r--r--lldb/source/Core/FileSpec.cpp580
-rw-r--r--lldb/source/Core/FileSpecList.cpp228
-rw-r--r--lldb/source/Core/Flags.cpp122
-rw-r--r--lldb/source/Core/InputReader.cpp343
-rw-r--r--lldb/source/Core/Language.cpp150
-rw-r--r--lldb/source/Core/Listener.cpp480
-rw-r--r--lldb/source/Core/Log.cpp590
-rw-r--r--lldb/source/Core/Mangled.cpp733
-rw-r--r--lldb/source/Core/Module.cpp515
-rw-r--r--lldb/source/Core/ModuleChild.cpp52
-rw-r--r--lldb/source/Core/ModuleList.cpp626
-rw-r--r--lldb/source/Core/Options.cpp700
-rw-r--r--lldb/source/Core/PluginManager.cpp1133
-rw-r--r--lldb/source/Core/RegularExpression.cpp154
-rw-r--r--lldb/source/Core/Scalar.cpp2084
-rw-r--r--lldb/source/Core/SearchFilter.cpp435
-rw-r--r--lldb/source/Core/Section.cpp791
-rw-r--r--lldb/source/Core/SourceManager.cpp305
-rw-r--r--lldb/source/Core/State.cpp87
-rw-r--r--lldb/source/Core/Stream.cpp776
-rw-r--r--lldb/source/Core/StreamFile.cpp132
-rw-r--r--lldb/source/Core/StreamString.cpp81
-rw-r--r--lldb/source/Core/StringList.cpp200
-rw-r--r--lldb/source/Core/TTYState.cpp203
-rw-r--r--lldb/source/Core/Timer.cpp235
-rw-r--r--lldb/source/Core/UUID.cpp218
-rw-r--r--lldb/source/Core/UserID.cpp73
-rw-r--r--lldb/source/Core/VMRange.cpp100
-rw-r--r--lldb/source/Core/Value.cpp803
-rw-r--r--lldb/source/Core/ValueObject.cpp678
-rw-r--r--lldb/source/Core/ValueObjectChild.cpp207
-rw-r--r--lldb/source/Core/ValueObjectList.cpp119
-rw-r--r--lldb/source/Core/ValueObjectRegister.cpp331
-rw-r--r--lldb/source/Core/ValueObjectVariable.cpp167
-rw-r--r--lldb/source/Expression/ClangASTSource.cpp101
-rw-r--r--lldb/source/Expression/ClangExpression.cpp633
-rw-r--r--lldb/source/Expression/ClangExpressionDeclMap.cpp246
-rw-r--r--lldb/source/Expression/ClangExpressionVariable.cpp100
-rw-r--r--lldb/source/Expression/ClangFunction.cpp671
-rw-r--r--lldb/source/Expression/ClangStmtVisitor.cpp1032
-rw-r--r--lldb/source/Expression/DWARFExpression.cpp2589
-rw-r--r--lldb/source/Expression/RecordingMemoryManager.cpp131
-rw-r--r--lldb/source/Host/macosx/Condition.cpp106
-rw-r--r--lldb/source/Host/macosx/Host.mm803
-rw-r--r--lldb/source/Host/macosx/Mutex.cpp244
-rw-r--r--lldb/source/Host/macosx/Symbols.cpp462
-rw-r--r--lldb/source/Host/macosx/TimeValue.cpp179
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCBundle.cpp83
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCBundle.h47
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCData.cpp82
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCData.h35
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCMutableArray.cpp123
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCMutableArray.h34
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp491
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.h77
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCMutableSet.cpp114
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCMutableSet.h53
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCReleaser.h155
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCString.cpp195
-rw-r--r--lldb/source/Host/macosx/cfcpp/CFCString.h41
-rw-r--r--lldb/source/Host/macosx/cfcpp/CoreFoundationCPP.h30
-rw-r--r--lldb/source/Interpreter/CommandCompletions.cpp414
-rw-r--r--lldb/source/Interpreter/CommandContext.cpp77
-rw-r--r--lldb/source/Interpreter/CommandInterpreter.cpp1300
-rw-r--r--lldb/source/Interpreter/CommandObject.cpp448
-rw-r--r--lldb/source/Interpreter/CommandObjectCrossref.cpp92
-rw-r--r--lldb/source/Interpreter/CommandObjectMultiword.cpp263
-rw-r--r--lldb/source/Interpreter/CommandObjectRegexCommand.cpp123
-rw-r--r--lldb/source/Interpreter/CommandReturnObject.cpp175
-rw-r--r--lldb/source/Interpreter/ScriptInterpreter.cpp66
-rw-r--r--lldb/source/Interpreter/ScriptInterpreterNone.cpp38
-rw-r--r--lldb/source/Interpreter/ScriptInterpreterPython.cpp830
-rw-r--r--lldb/source/Interpreter/StateVariable.cpp320
-rw-r--r--lldb/source/Interpreter/embedded_interpreter.py90
-rw-r--r--lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp578
-rw-r--r--lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h93
-rw-r--r--lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp412
-rw-r--r--lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h92
-rw-r--r--lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp468
-rw-r--r--lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.h111
-rw-r--r--lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp1129
-rw-r--r--lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h360
-rw-r--r--lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.cpp72
-rw-r--r--lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.h34
-rw-r--r--lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.cpp328
-rw-r--r--lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.h133
-rw-r--r--lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.cpp151
-rw-r--r--lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.h94
-rw-r--r--lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp428
-rw-r--r--lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h183
-rw-r--r--lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp259
-rw-r--r--lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h103
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp929
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h197
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/elf.h240
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp1311
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h131
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/scripts/cc-swig47
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/scripts/config.pl71
-rwxr-xr-xlldb/source/Plugins/Process/MacOSX-User/scripts/test-ProcessDebug.pl409
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.cpp575
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.h148
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.cpp674
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.h138
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext.h48
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.cpp1884
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.h63
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.cpp245
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.h57
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.cpp255
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.h72
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.cpp195
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.h36
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.cpp183
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.h63
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/ProcessControl-mig.defs16
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.cpp2228
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.h490
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.cpp124
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.h62
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.cpp1819
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.h206
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.cpp1448
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.h302
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.cpp1202
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.h256
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.cpp1328
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.h261
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp769
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.h159
-rw-r--r--lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.cpp327
-rw-r--r--lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.h83
-rw-r--r--lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.cpp306
-rw-r--r--lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.h22
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp255
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h83
-rw-r--r--lldb/source/Plugins/Process/Utility/UnwindLibUnwind.cpp73
-rw-r--r--lldb/source/Plugins/Process/Utility/UnwindLibUnwind.h66
-rw-r--r--lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp243
-rw-r--r--lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h77
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/include/libunwind.h509
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/include/mach-o/compact_unwind_encoding.h212
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/include/unwind.h213
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp456
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/ArchDefaultUnwinder.hpp115
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp147
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyParser.hpp409
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp1019
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/DwarfInstructions.hpp1686
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/DwarfParser.hpp869
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/FileAbstraction.hpp135
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/InternalMacros.h89
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/Registers.hpp985
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/Registers.s261
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/RemoteDebuggerDummyUnwinder.hpp88
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/RemoteProcInfo.hpp977
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/RemoteRegisterMap.hpp405
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/RemoteUnwindProfile.h85
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/Unwind-sjlj.c466
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp1307
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1-gcc-ext.c282
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1.c443
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/dwarf2.h245
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/libunwind_priv.h35
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/libuwind.cxx421
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/unw_getcontext.s229
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp813
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h270
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp508
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h250
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBServer.cpp1148
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBServerLog.cpp80
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBServerLog.h55
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp2272
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h404
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp121
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h53
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp296
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h156
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp211
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h77
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h45
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp770
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h168
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp56
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h48
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp202
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h74
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp274
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h70
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp343
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h98
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp1206
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h86
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp1929
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h320
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp1410
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h225
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp48
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h29
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp132
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h57
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp297
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h38
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp166
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h91
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp275
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h89
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.c2224
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h252
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp571
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h81
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp172
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h24
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp89
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h34
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp207
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h91
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp3615
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h331
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp873
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h186
-rw-r--r--lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp401
-rw-r--r--lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h136
-rw-r--r--lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp339
-rw-r--r--lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h71
-rw-r--r--lldb/source/Symbol/Block.cpp641
-rw-r--r--lldb/source/Symbol/ClangASTContext.cpp2552
-rw-r--r--lldb/source/Symbol/CompileUnit.cpp366
-rw-r--r--lldb/source/Symbol/DWARFCallFrameInfo.cpp1344
-rw-r--r--lldb/source/Symbol/Declaration.cpp172
-rw-r--r--lldb/source/Symbol/Function.cpp432
-rw-r--r--lldb/source/Symbol/LineEntry.cpp237
-rw-r--r--lldb/source/Symbol/LineTable.cpp332
-rw-r--r--lldb/source/Symbol/ObjectFile.cpp92
-rw-r--r--lldb/source/Symbol/Symbol.cpp463
-rw-r--r--lldb/source/Symbol/SymbolContext.cpp424
-rw-r--r--lldb/source/Symbol/SymbolFile.cpp50
-rw-r--r--lldb/source/Symbol/SymbolVendor.mm386
-rw-r--r--lldb/source/Symbol/Symtab.cpp596
-rw-r--r--lldb/source/Symbol/Type.cpp1531
-rw-r--r--lldb/source/Symbol/TypeList.cpp239
-rw-r--r--lldb/source/Symbol/Variable.cpp167
-rw-r--r--lldb/source/Symbol/VariableList.cpp116
-rw-r--r--lldb/source/Target/ABI.cpp47
-rw-r--r--lldb/source/Target/ExecutionContext.cpp107
-rw-r--r--lldb/source/Target/ObjCObjectPrinter.cpp120
-rw-r--r--lldb/source/Target/PathMappingList.cpp125
-rw-r--r--lldb/source/Target/Process.cpp1876
-rw-r--r--lldb/source/Target/RegisterContext.cpp238
-rw-r--r--lldb/source/Target/StackFrame.cpp393
-rw-r--r--lldb/source/Target/StackFrameList.cpp135
-rw-r--r--lldb/source/Target/StackID.cpp110
-rw-r--r--lldb/source/Target/Target.cpp707
-rw-r--r--lldb/source/Target/TargetList.cpp342
-rw-r--r--lldb/source/Target/Thread.cpp1121
-rw-r--r--lldb/source/Target/ThreadList.cpp460
-rw-r--r--lldb/source/Target/ThreadPlan.cpp185
-rw-r--r--lldb/source/Target/ThreadPlanBase.cpp202
-rw-r--r--lldb/source/Target/ThreadPlanCallFunction.cpp250
-rw-r--r--lldb/source/Target/ThreadPlanContinue.cpp120
-rw-r--r--lldb/source/Target/ThreadPlanRunToAddress.cpp176
-rw-r--r--lldb/source/Target/ThreadPlanShouldStopHere.cpp53
-rw-r--r--lldb/source/Target/ThreadPlanStepInRange.cpp154
-rw-r--r--lldb/source/Target/ThreadPlanStepInstruction.cpp191
-rw-r--r--lldb/source/Target/ThreadPlanStepOut.cpp228
-rw-r--r--lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp130
-rw-r--r--lldb/source/Target/ThreadPlanStepOverRange.cpp119
-rw-r--r--lldb/source/Target/ThreadPlanStepRange.cpp263
-rw-r--r--lldb/source/Target/ThreadPlanStepThrough.cpp137
-rw-r--r--lldb/source/Target/ThreadPlanStepUntil.cpp360
-rw-r--r--lldb/source/Target/UnixSignals.cpp310
-rw-r--r--lldb/source/Utility/ARM_DWARF_Registers.h190
-rw-r--r--lldb/source/Utility/ARM_GCC_Registers.h35
-rw-r--r--lldb/source/Utility/PseudoTerminal.cpp336
-rw-r--r--lldb/source/Utility/PseudoTerminal.h267
-rw-r--r--lldb/source/Utility/StringExtractor.cpp360
-rw-r--r--lldb/source/Utility/StringExtractor.h126
-rw-r--r--lldb/source/Utility/StringExtractorGDBRemote.cpp89
-rw-r--r--lldb/source/Utility/StringExtractorGDBRemote.h73
-rw-r--r--lldb/source/lldb-log.cpp190
-rw-r--r--lldb/source/lldb.cpp107
-rw-r--r--lldb/test/Makefile21
-rw-r--r--lldb/test/array_types/Makefile125
-rw-r--r--lldb/test/array_types/cmds.txt3
-rw-r--r--lldb/test/array_types/main.c51
-rw-r--r--lldb/test/bitfields/Makefile125
-rw-r--r--lldb/test/bitfields/main.c44
-rw-r--r--lldb/test/class_types/Makefile125
-rw-r--r--lldb/test/class_types/cmds.txt3
-rw-r--r--lldb/test/class_types/main.cpp106
-rw-r--r--lldb/test/dead-strip/Makefile126
-rw-r--r--lldb/test/dead-strip/cmds.txt4
-rw-r--r--lldb/test/dead-strip/main.c53
-rw-r--r--lldb/test/enum_types/Makefile125
-rw-r--r--lldb/test/enum_types/main.c29
-rw-r--r--lldb/test/function_types/Makefile125
-rw-r--r--lldb/test/function_types/main.c22
-rw-r--r--lldb/test/global_variables/Makefile142
-rw-r--r--lldb/test/global_variables/a.c10
-rw-r--r--lldb/test/global_variables/cmds.txt3
-rw-r--r--lldb/test/global_variables/main.c21
-rw-r--r--lldb/test/load_unload/Makefile33
-rw-r--r--lldb/test/load_unload/a.c15
-rw-r--r--lldb/test/load_unload/b.c13
-rw-r--r--lldb/test/load_unload/c.c13
-rw-r--r--lldb/test/load_unload/cmds.txt2
-rw-r--r--lldb/test/load_unload/main.c72
-rw-r--r--lldb/test/namespace/Makefile125
-rw-r--r--lldb/test/namespace/cmds.txt3
-rw-r--r--lldb/test/namespace/main.cpp69
-rw-r--r--lldb/test/order/Makefile127
-rw-r--r--lldb/test/order/cmds.txt3
-rw-r--r--lldb/test/order/main.c54
-rw-r--r--lldb/test/order/order-file4
-rw-r--r--lldb/test/print-obj/Makefile125
-rw-r--r--lldb/test/print-obj/blocked.m73
-rw-r--r--lldb/test/set_values/Makefile125
-rw-r--r--lldb/test/set_values/main.c116
-rw-r--r--lldb/test/signed_types/Makefile125
-rw-r--r--lldb/test/signed_types/main.cpp31
-rw-r--r--lldb/test/stl/Makefile125
-rw-r--r--lldb/test/stl/cmds.txt3
-rw-r--r--lldb/test/stl/main.cpp15
-rw-r--r--lldb/test/struct_types/Makefile125
-rw-r--r--lldb/test/struct_types/cmds.txt3
-rw-r--r--lldb/test/struct_types/main.c23
-rwxr-xr-xlldb/test/tester.py107
-rw-r--r--lldb/test/threads/Makefile125
-rw-r--r--lldb/test/threads/main.cpp129
-rw-r--r--lldb/test/unsigned_types/Makefile125
-rw-r--r--lldb/test/unsigned_types/main.cpp22
-rw-r--r--lldb/tools/debugserver/debugnub-exports2
-rw-r--r--lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj604
-rw-r--r--lldb/tools/debugserver/resources/lldb-debugserver-Info.plist21
-rw-r--r--lldb/tools/debugserver/resources/lldb-debugserver-entitlements.plist8
-rw-r--r--lldb/tools/debugserver/scripts/dbgnub-config.pl71
-rw-r--r--lldb/tools/debugserver/source/ChangeLog1515
-rw-r--r--lldb/tools/debugserver/source/DNB.cpp1996
-rw-r--r--lldb/tools/debugserver/source/DNB.h141
-rw-r--r--lldb/tools/debugserver/source/DNBArch.h61
-rw-r--r--lldb/tools/debugserver/source/DNBBreakpoint.cpp303
-rw-r--r--lldb/tools/debugserver/source/DNBBreakpoint.h159
-rw-r--r--lldb/tools/debugserver/source/DNBDataRef.cpp485
-rw-r--r--lldb/tools/debugserver/source/DNBDataRef.h111
-rw-r--r--lldb/tools/debugserver/source/DNBDefs.h331
-rw-r--r--lldb/tools/debugserver/source/DNBError.cpp108
-rw-r--r--lldb/tools/debugserver/source/DNBError.h96
-rw-r--r--lldb/tools/debugserver/source/DNBLog.cpp309
-rw-r--r--lldb/tools/debugserver/source/DNBLog.h96
-rw-r--r--lldb/tools/debugserver/source/DNBRegisterInfo.cpp220
-rw-r--r--lldb/tools/debugserver/source/DNBRegisterInfo.h31
-rw-r--r--lldb/tools/debugserver/source/DNBRuntimeAction.h25
-rw-r--r--lldb/tools/debugserver/source/DNBThreadResumeActions.cpp116
-rw-r--r--lldb/tools/debugserver/source/DNBThreadResumeActions.h95
-rw-r--r--lldb/tools/debugserver/source/DNBTimer.h162
-rw-r--r--lldb/tools/debugserver/source/FunctionProfiler.cpp288
-rw-r--r--lldb/tools/debugserver/source/FunctionProfiler.h70
-rw-r--r--lldb/tools/debugserver/source/MacOSX/CFBundle.cpp87
-rw-r--r--lldb/tools/debugserver/source/MacOSX/CFBundle.h37
-rw-r--r--lldb/tools/debugserver/source/MacOSX/CFData.cpp85
-rw-r--r--lldb/tools/debugserver/source/MacOSX/CFData.h39
-rw-r--r--lldb/tools/debugserver/source/MacOSX/CFString.cpp201
-rw-r--r--lldb/tools/debugserver/source/MacOSX/CFString.h43
-rw-r--r--lldb/tools/debugserver/source/MacOSX/CFUtils.h81
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachDYLD.cpp679
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachDYLD.h145
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachException.cpp533
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachException.h147
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.cpp2008
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.h263
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachTask.cpp660
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachTask.h91
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachThread.cpp745
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachThread.h124
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp432
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachThreadList.h71
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp186
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachVMMemory.h40
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp179
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachVMRegion.h67
-rw-r--r--lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp2610
-rw-r--r--lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h217
-rw-r--r--lldb/tools/debugserver/source/MacOSX/dbgnub-mig.defs16
-rw-r--r--lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp879
-rw-r--r--lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h196
-rw-r--r--lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp569
-rw-r--r--lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.h180
-rw-r--r--lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp1035
-rw-r--r--lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h199
-rw-r--r--lldb/tools/debugserver/source/PThreadCondition.h53
-rw-r--r--lldb/tools/debugserver/source/PThreadEvent.cpp227
-rw-r--r--lldb/tools/debugserver/source/PThreadEvent.h59
-rw-r--r--lldb/tools/debugserver/source/PThreadMutex.cpp84
-rw-r--r--lldb/tools/debugserver/source/PThreadMutex.h148
-rw-r--r--lldb/tools/debugserver/source/ProfileObjectiveC.cpp393
-rw-r--r--lldb/tools/debugserver/source/ProfileObjectiveC.h82
-rw-r--r--lldb/tools/debugserver/source/PseudoTerminal.cpp226
-rw-r--r--lldb/tools/debugserver/source/PseudoTerminal.h94
-rw-r--r--lldb/tools/debugserver/source/RNBContext.cpp230
-rw-r--r--lldb/tools/debugserver/source/RNBContext.h123
-rw-r--r--lldb/tools/debugserver/source/RNBDefs.h78
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.cpp3187
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.h309
-rw-r--r--lldb/tools/debugserver/source/RNBServices.cpp145
-rw-r--r--lldb/tools/debugserver/source/RNBServices.h29
-rw-r--r--lldb/tools/debugserver/source/RNBSocket.cpp251
-rw-r--r--lldb/tools/debugserver/source/RNBSocket.h65
-rw-r--r--lldb/tools/debugserver/source/SysSignal.cpp66
-rw-r--r--lldb/tools/debugserver/source/SysSignal.h23
-rw-r--r--lldb/tools/debugserver/source/TTYState.cpp122
-rw-r--r--lldb/tools/debugserver/source/TTYState.h61
-rw-r--r--lldb/tools/debugserver/source/com.apple.debugserver.applist.plist16
-rw-r--r--lldb/tools/debugserver/source/com.apple.debugserver.plist15
-rw-r--r--lldb/tools/debugserver/source/debugserver-entitlements.plist14
-rw-r--r--lldb/tools/debugserver/source/debugserver.cpp1219
-rw-r--r--lldb/tools/driver/Driver.cpp1265
-rw-r--r--lldb/tools/driver/Driver.h156
-rw-r--r--lldb/tools/driver/IOChannel.cpp449
-rw-r--r--lldb/tools/driver/IOChannel.h113
-rw-r--r--lldb/tools/driver/lldb-Info.plist21
-rw-r--r--lldb/www/content.css25
-rw-r--r--lldb/www/index.html197
-rw-r--r--lldb/www/menu.css39
-rw-r--r--lldb/www/menu.html.incl20
790 files changed, 216273 insertions, 0 deletions
diff --git a/lldb/docs/code-signing.txt b/lldb/docs/code-signing.txt
new file mode 100644
index 00000000000..77cc0999324
--- /dev/null
+++ b/lldb/docs/code-signing.txt
@@ -0,0 +1,47 @@
+On MacOSX lldb needs to be code signed. The Debug and Release builds
+are set to code sign using a code signing certificate named
+lldb_codesign.
+
+If you don't have one yet you will need to:
+- Launch /Applications/Utilities/Keychain Access.app
+
+- In Keychain Access select the "login" keychain in the "Keychains"
+ list in the upper left hand corner of the window.
+
+- Select the following menu item:
+
+ Keychain Access->Certificate Assistant->Create a Certificate...
+
+- Set the following settings
+
+ Name = lldb_codesign
+ Identity Type = Self Signed Root
+ Certificate Type = Code Signing
+
+- Click Continue
+- Click Continue
+- Click Done
+- Click on the "My Certificates"
+- Double click on your new lldb_codesign certificate
+- Turn down the "Trust" disclosure triangle
+
+ Change:
+ When using this certificate: Always Trust
+
+- Enter your login password to confirm and make it trusted
+
+The next steps are necessary on SnowLeopard, but are probably because of a bug
+how Keychain Access makes certificates (the steps above used to be enougnk
+in Leopard.)
+
+- Option-drag the new lldb_codesign certificate from the login keychain to
+ the System keychain in the Keychains pane of the main Keychain Access window
+ to make a copy of this certificate in the System keychain. You'll have to
+ authorize a few more times, set it to be "Always trusted" when asked.
+- Switch to the System keychain, and drag the copy of lldb_codesign you just
+ made there onto the desktop.
+- Switch to Terminal, and run the following:
+
+sudo security add-trust -d -r trustRoot -p basic -p codeSign -k /Library/Keychains/System.keychain ~/Desktop/lldb_codesign.cer
+
+That should do it.
diff --git a/lldb/docs/code_signing.txt b/lldb/docs/code_signing.txt
new file mode 100644
index 00000000000..77cc0999324
--- /dev/null
+++ b/lldb/docs/code_signing.txt
@@ -0,0 +1,47 @@
+On MacOSX lldb needs to be code signed. The Debug and Release builds
+are set to code sign using a code signing certificate named
+lldb_codesign.
+
+If you don't have one yet you will need to:
+- Launch /Applications/Utilities/Keychain Access.app
+
+- In Keychain Access select the "login" keychain in the "Keychains"
+ list in the upper left hand corner of the window.
+
+- Select the following menu item:
+
+ Keychain Access->Certificate Assistant->Create a Certificate...
+
+- Set the following settings
+
+ Name = lldb_codesign
+ Identity Type = Self Signed Root
+ Certificate Type = Code Signing
+
+- Click Continue
+- Click Continue
+- Click Done
+- Click on the "My Certificates"
+- Double click on your new lldb_codesign certificate
+- Turn down the "Trust" disclosure triangle
+
+ Change:
+ When using this certificate: Always Trust
+
+- Enter your login password to confirm and make it trusted
+
+The next steps are necessary on SnowLeopard, but are probably because of a bug
+how Keychain Access makes certificates (the steps above used to be enougnk
+in Leopard.)
+
+- Option-drag the new lldb_codesign certificate from the login keychain to
+ the System keychain in the Keychains pane of the main Keychain Access window
+ to make a copy of this certificate in the System keychain. You'll have to
+ authorize a few more times, set it to be "Always trusted" when asked.
+- Switch to the System keychain, and drag the copy of lldb_codesign you just
+ made there onto the desktop.
+- Switch to Terminal, and run the following:
+
+sudo security add-trust -d -r trustRoot -p basic -p codeSign -k /Library/Keychains/System.keychain ~/Desktop/lldb_codesign.cer
+
+That should do it.
diff --git a/lldb/include/lldb/API/LLDB.h b/lldb/include/lldb/API/LLDB.h
new file mode 100644
index 00000000000..729d393f5ef
--- /dev/null
+++ b/lldb/include/lldb/API/LLDB.h
@@ -0,0 +1,49 @@
+//===-- 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/SBDefines.h>
+#include <LLDB/SBAddress.h>
+#include <LLDB/SBBlock.h>
+#include <LLDB/SBBreakpoint.h>
+#include <LLDB/SBBreakpointLocation.h>
+#include <LLDB/SBBroadcaster.h>
+#include <LLDB/SBCommandContext.h>
+#include <LLDB/SBCommandInterpreter.h>
+#include <LLDB/SBCommandReturnObject.h>
+#include <LLDB/SBCommunication.h>
+#include <LLDB/SBCompileUnit.h>
+#include <LLDB/SBDebugger.h>
+#include <LLDB/SBError.h>
+#include <LLDB/SBEvent.h>
+#include <LLDB/SBFileSpec.h>
+#include <LLDB/SBFrame.h>
+#include <LLDB/SBFunction.h>
+#include <LLDB/SBHostOS.h>
+#include <LLDB/SBInputReader.h>
+#include <LLDB/SBLineEntry.h>
+#include <LLDB/SBListener.h>
+#include <LLDB/SBModule.h>
+#include <LLDB/SBProcess.h>
+#include <LLDB/SBSourceManager.h>
+#include <LLDB/SBSymbol.h>
+#include <LLDB/SBSymbolContext.h>
+#include <LLDB/SBTarget.h>
+#include <LLDB/SBThread.h>
+#include <LLDB/SBType.h>
+#include <LLDB/SBValue.h>
+#include <LLDB/SBValueList.h>
+
+#endif // LLDB_LLDB_h_
diff --git a/lldb/include/lldb/API/SBAddress.h b/lldb/include/lldb/API/SBAddress.h
new file mode 100644
index 00000000000..4f0195aa561
--- /dev/null
+++ b/lldb/include/lldb/API/SBAddress.h
@@ -0,0 +1,75 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBAddress
+{
+public:
+
+ SBAddress ();
+
+ SBAddress (const lldb::SBAddress &rhs);
+
+ ~SBAddress ();
+
+#ifndef SWIG
+ const SBAddress &
+ operator = (const SBAddress &rhs);
+#endif
+
+ bool
+ IsValid () const;
+
+ addr_t
+ GetFileAddress () const;
+
+ addr_t
+ GetLoadAddress (const lldb::SBProcess &process) const;
+
+ bool
+ OffsetAddress (addr_t offset);
+
+protected:
+
+ friend class SBFrame;
+ friend class SBLineEntry;
+ friend class SBSymbolContext;
+ friend class SBThread;
+
+#ifndef SWIG
+
+ const lldb_private::Address *
+ operator->() const;
+
+ const lldb_private::Address &
+ operator*() const;
+
+#endif
+
+
+ SBAddress (const lldb_private::Address *lldb_object_ptr);
+
+ void
+ SetAddress (const lldb_private::Address *lldb_object_ptr);
+
+private:
+
+ std::auto_ptr<lldb_private::Address> m_lldb_object_ap;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBAddress_h_
diff --git a/lldb/include/lldb/API/SBBlock.h b/lldb/include/lldb/API/SBBlock.h
new file mode 100644
index 00000000000..b8eef00d72e
--- /dev/null
+++ b/lldb/include/lldb/API/SBBlock.h
@@ -0,0 +1,44 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBBlock
+{
+public:
+
+ SBBlock ();
+
+ ~SBBlock ();
+
+ bool
+ IsValid () const;
+
+ void
+ AppendVariables (bool can_create, bool get_parent_variables, lldb_private::VariableList *var_list);
+
+private:
+ friend class SBFrame;
+ friend class SBSymbolContext;
+
+ SBBlock (lldb_private::Block *lldb_object_ptr);
+
+
+ lldb_private::Block *m_lldb_object_ptr;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBBlock_h_
diff --git a/lldb/include/lldb/API/SBBreakpoint.h b/lldb/include/lldb/API/SBBreakpoint.h
new file mode 100644
index 00000000000..71394749e0a
--- /dev/null
+++ b/lldb/include/lldb/API/SBBreakpoint.h
@@ -0,0 +1,129 @@
+//===-- 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/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();
+
+#ifndef SWIG
+ const SBBreakpoint &
+ operator = (const SBBreakpoint& rhs);
+#endif
+
+ break_id_t
+ GetID () const;
+
+ bool
+ IsValid() const;
+
+ void
+ Dump (FILE *f);
+
+ 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
+ ListLocations (FILE *, const char *description_level = "full");
+
+ void
+ SetEnabled (bool enable);
+
+ bool
+ IsEnabled ();
+
+ void
+ SetIgnoreCount (int32_t count);
+
+ int32_t
+ GetIgnoreCount () const;
+
+ void
+ SetThreadID (lldb::tid_t sb_thread_id);
+
+ lldb::tid_t
+ GetThreadID ();
+
+ void
+ SetCallback (BreakpointHitCallback callback, void *baton);
+
+ size_t
+ GetNumResolvedLocations() const;
+
+ size_t
+ GetNumLocations() const;
+
+ void
+ GetDescription (FILE *, const char *description_level, bool describe_locations = false);
+
+
+
+private:
+ friend class SBBreakpointLocation;
+ friend class SBTarget;
+
+ SBBreakpoint (const lldb::BreakpointSP &bp_sp);
+
+#ifndef SWIG
+
+ lldb_private::Breakpoint *
+ operator->() const;
+
+ lldb_private::Breakpoint *
+ get() const;
+
+ lldb::BreakpointSP &
+ operator *();
+
+ const lldb::BreakpointSP &
+ operator *() const;
+
+#endif
+
+ 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_break_sp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBBreakpoint_h_
diff --git a/lldb/include/lldb/API/SBBreakpointLocation.h b/lldb/include/lldb/API/SBBreakpointLocation.h
new file mode 100644
index 00000000000..836995676a3
--- /dev/null
+++ b/lldb/include/lldb/API/SBBreakpointLocation.h
@@ -0,0 +1,73 @@
+//===-- 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/SBDefines.h>
+#include <LLDB/SBBreakpoint.h>
+
+namespace lldb {
+
+class SBBreakpointLocation
+{
+public:
+
+ SBBreakpointLocation ();
+
+ ~SBBreakpointLocation ();
+
+ bool
+ IsValid() const;
+
+ lldb::addr_t
+ GetLoadAddress ();
+
+ void
+ SetEnabled(bool enabled);
+
+ bool
+ IsEnabled ();
+
+ int32_t
+ GetIgnoreCount ();
+
+ void
+ SetIgnoreCount (int32_t n);
+
+ void
+ SetThreadID (lldb::tid_t thread_id);
+
+ lldb::tid_t
+ GetThreadID ();
+
+ bool
+ IsResolved ();
+
+ void
+ GetDescription (FILE *f, const char *description_level);
+
+ SBBreakpoint
+ GetBreakpoint ();
+
+private:
+ friend class SBBreakpoint;
+
+ SBBreakpointLocation (const lldb::BreakpointLocationSP &break_loc_sp);
+
+ void
+ SetLocation (const lldb::BreakpointLocationSP &break_loc_sp);
+
+ lldb::BreakpointLocationSP m_break_loc_sp;
+
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBBreakpointLocation_h_
diff --git a/lldb/include/lldb/API/SBBroadcaster.h b/lldb/include/lldb/API/SBBroadcaster.h
new file mode 100644
index 00000000000..94baef2f015
--- /dev/null
+++ b/lldb/include/lldb/API/SBBroadcaster.h
@@ -0,0 +1,83 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBBroadcaster
+{
+public:
+ SBBroadcaster ();
+
+ SBBroadcaster (const char *name);
+
+ ~SBBroadcaster();
+
+ bool
+ IsValid () const;
+
+ 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 ();
+
+ bool
+ EventTypeHasListeners (uint32_t event_type);
+
+ bool
+ RemoveListener (const lldb::SBListener &listener, uint32_t event_mask = UINT32_MAX);
+
+#ifndef SWIG
+ bool
+ operator == (const lldb::SBBroadcaster &rhs) const;
+
+ bool
+ operator != (const lldb::SBBroadcaster &rhs) const;
+
+#endif
+
+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 *
+ GetLLDBObjectPtr () const;
+
+ void
+ SetLLDBObjectPtr (lldb_private::Broadcaster *broadcaster, bool owns);
+
+private:
+
+ lldb_private::Broadcaster *m_lldb_object;
+ bool m_lldb_object_owned;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBBroadcaster_h_
diff --git a/lldb/include/lldb/API/SBCommandContext.h b/lldb/include/lldb/API/SBCommandContext.h
new file mode 100644
index 00000000000..c77465cbd7a
--- /dev/null
+++ b/lldb/include/lldb/API/SBCommandContext.h
@@ -0,0 +1,36 @@
+//===-- SBCommandContext.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_SBCommandContext_h_
+#define LLDB_SBCommandContext_h_
+
+
+#include <LLDB/SBDefines.h>
+
+namespace lldb {
+
+class SBCommandContext
+{
+public:
+
+ SBCommandContext (lldb_private::CommandContext *lldb_object);
+
+ ~SBCommandContext ();
+
+ bool
+ IsValid () const;
+
+private:
+
+ lldb_private::CommandContext *m_lldb_object;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBCommandContext_h_
diff --git a/lldb/include/lldb/API/SBCommandInterpreter.h b/lldb/include/lldb/API/SBCommandInterpreter.h
new file mode 100644
index 00000000000..bb71cf59d27
--- /dev/null
+++ b/lldb/include/lldb/API/SBCommandInterpreter.h
@@ -0,0 +1,105 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBCommandInterpreter
+{
+public:
+ enum
+ {
+ eBroadcastBitThreadShouldExit = (1 << 0),
+ eBroadcastBitResetPrompt = (1 << 1),
+ eBroadcastBitQuitCommandReceived = (1 << 2) // User entered quit
+ };
+
+
+ ~SBCommandInterpreter ();
+
+ bool
+ CommandExists (const char *cmd);
+
+ bool
+ AliasExists (const char *cmd);
+
+ bool
+ UserCommandExists (const char *cmd);
+
+ lldb::SBBroadcaster
+ GetBroadcaster ();
+
+ const char **
+ GetEnvironmentVariables ();
+
+ bool
+ HasCommands ();
+
+ bool
+ HasAliases ();
+
+ bool
+ HasUserCommands ();
+
+ bool
+ HasAliasOptions ();
+
+ bool
+ HasInterpreterVariables ();
+
+ lldb::SBProcess
+ GetProcess ();
+
+ ssize_t
+ WriteToScriptInterpreter (const char *src);
+
+ ssize_t
+ WriteToScriptInterpreter (const char *src, size_t src_len);
+
+ 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);
+
+ int
+ HandleCompletion (const char *current_line,
+ const char *cursor,
+ const char *last_char,
+ int match_start_point,
+ int max_return_elements,
+ SBStringList &matches);
+
+protected:
+
+ lldb_private::CommandInterpreter &
+ GetLLDBObjectRef ();
+
+ lldb_private::CommandInterpreter *
+ GetLLDBObjectPtr ();
+
+private:
+ friend class SBDebugger;
+
+ SBCommandInterpreter (lldb_private::CommandInterpreter &interpreter_ptr); // Access using SBDebugger::GetSharedInstance().GetCommandInterpreter();
+
+ lldb_private::CommandInterpreter &m_interpreter;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBCommandInterpreter_h_
diff --git a/lldb/include/lldb/API/SBCommandReturnObject.h b/lldb/include/lldb/API/SBCommandReturnObject.h
new file mode 100644
index 00000000000..65ddc70c124
--- /dev/null
+++ b/lldb/include/lldb/API/SBCommandReturnObject.h
@@ -0,0 +1,80 @@
+//===-- 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 <LLDB/SBDefines.h>
+
+namespace lldb {
+
+class SBCommandReturnObject
+{
+public:
+
+ SBCommandReturnObject ();
+
+ ~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();
+
+ bool
+ Succeeded ();
+
+ bool
+ HasResult ();
+
+ void
+ AppendMessage (const char *message);
+
+protected:
+ friend class SBCommandInterpreter;
+ friend class SBOptions;
+
+ lldb_private::CommandReturnObject *
+ GetLLDBObjectPtr();
+
+ lldb_private::CommandReturnObject &
+ GetLLDBObjectRef();
+
+ void
+ SetLLDBObjectPtr (lldb_private::CommandReturnObject *ptr);
+
+ private:
+ std::auto_ptr<lldb_private::CommandReturnObject> m_return_object_ap;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBCommandReturnObject_h_
diff --git a/lldb/include/lldb/API/SBCommunication.h b/lldb/include/lldb/API/SBCommunication.h
new file mode 100644
index 00000000000..134a78a557d
--- /dev/null
+++ b/lldb/include/lldb/API/SBCommunication.h
@@ -0,0 +1,97 @@
+//===-- 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/SBDefines.h>
+#include <LLDB/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 ();
+
+
+ lldb::SBBroadcaster
+ GetBroadcaster ();
+
+ lldb::ConnectionStatus
+ AdoptFileDesriptor (int fd, bool owns_fd);
+
+ lldb::ConnectionStatus
+ CheckIfBytesAvailable ();
+
+ lldb::ConnectionStatus
+ WaitForBytesAvailableInfinite ();
+
+ lldb::ConnectionStatus
+ WaitForBytesAvailableWithTimeout (uint32_t timeout_usec);
+
+ lldb::ConnectionStatus
+ Connect (const char *url);
+
+ lldb::ConnectionStatus
+ Disconnect ();
+
+ bool
+ IsConnected () const;
+
+ 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:
+// void
+// CreateIfNeeded ();
+
+ lldb_private::Communication *m_lldb_object;
+ bool m_lldb_object_owned;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBCommunication_h_
diff --git a/lldb/include/lldb/API/SBCompileUnit.h b/lldb/include/lldb/API/SBCompileUnit.h
new file mode 100644
index 00000000000..3d6e7e48b91
--- /dev/null
+++ b/lldb/include/lldb/API/SBCompileUnit.h
@@ -0,0 +1,75 @@
+//===-- 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/SBDefines.h>
+#include <LLDB/SBFileSpec.h>
+
+namespace lldb {
+
+class SBCompileUnit
+{
+public:
+
+ SBCompileUnit ();
+
+ ~SBCompileUnit ();
+
+ 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;
+
+#ifndef SWIG
+
+ bool
+ operator == (const lldb::SBCompileUnit &rhs) const;
+
+ bool
+ operator != (const lldb::SBCompileUnit &rhs) const;
+
+#endif
+
+private:
+ friend class SBFrame;
+ friend class SBSymbolContext;
+
+ SBCompileUnit (lldb_private::CompileUnit *lldb_object_ptr);
+
+#ifndef SWIG
+
+ const lldb_private::CompileUnit *
+ operator->() const;
+
+ const lldb_private::CompileUnit &
+ operator*() const;
+
+#endif
+
+ lldb_private::CompileUnit *m_lldb_object_ptr;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBCompileUnit_h_
diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h
new file mode 100644
index 00000000000..3dcc4890f5f
--- /dev/null
+++ b/lldb/include/lldb/API/SBDebugger.h
@@ -0,0 +1,148 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBDebugger
+{
+public:
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static void
+ SetAsync (bool b);
+
+ static void
+ SetInputFile (const char *tty_name); // DEPRECATED: will be removed in next submission
+
+ static void
+ SetOutputFile (const char *tty_name); // DEPRECATED: will be removed in next submission
+
+ static void
+ SetErrorFile (const char *tty_name); // DEPRECATED: will be removed in next submission
+
+ static void
+ SetInputFileHandle (FILE *f, bool transfer_ownership);
+
+ static void
+ SetOutputFileHandle (FILE *f, bool transfer_ownership);
+
+ static void
+ SetErrorFileHandle (FILE *f, bool transfer_ownership);
+
+ static FILE *
+ GetInputFileHandle ();
+
+ static FILE *
+ GetOutputFileHandle ();
+
+ static FILE *
+ GetErrorFileHandle ();
+
+ static lldb::SBCommandInterpreter
+ GetCommandInterpreter ();
+
+ static void
+ HandleCommand (const char *command);
+
+ static lldb::SBListener
+ GetListener ();
+
+ static void
+ HandleProcessEvent (const lldb::SBProcess &process,
+ const lldb::SBEvent &event,
+ FILE *out,
+ FILE *err);
+
+ static lldb::SBTarget
+ CreateTargetWithFileAndTargetTriple (const char *filename,
+ const char *target_triple);
+
+ static lldb::SBTarget
+ CreateTargetWithFileAndArch (const char *filename,
+ const char *archname);
+
+ static lldb::SBTarget
+ CreateTarget (const char *filename);
+
+ static lldb::SBTarget
+ GetTargetAtIndex (uint32_t idx);
+
+ static lldb::SBTarget
+ FindTargetWithProcessID (pid_t pid);
+
+ static lldb::SBTarget
+ FindTargetWithFileAndArch (const char *filename,
+ const char *arch);
+
+ static uint32_t
+ GetNumTargets ();
+
+ static lldb::SBTarget
+ GetCurrentTarget ();
+
+ static void
+ UpdateCurrentThread (lldb::SBProcess &process);
+
+ static void
+ ReportCurrentLocation (FILE *out = stdout,
+ FILE *err = stderr);
+
+ static lldb::SBSourceManager &
+ GetSourceManager ();
+
+ static bool
+ GetDefaultArchitecture (char *arch_name, size_t arch_name_len);
+
+ static bool
+ SetDefaultArchitecture (const char *arch_name);
+
+ static 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);
+
+ static void
+ DispatchInput (void *baton, const void *data, size_t data_len);
+
+ static void
+ PushInputReader (lldb::SBInputReader &reader);
+
+private:
+#ifndef SWIG
+ friend class SBProcess;
+
+ static lldb::SBTarget
+ FindTargetWithLLDBProcess (const lldb::ProcessSP &processSP);
+#endif
+}; // class SBDebugger
+
+
+} // namespace lldb
+
+#endif // LLDB_SBDebugger_h_
diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h
new file mode 100644
index 00000000000..f1e3c38a42e
--- /dev/null
+++ b/lldb/include/lldb/API/SBDefines.h
@@ -0,0 +1,62 @@
+//===-- 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-forward-rtti.h>
+#include <LLDB/lldb-types.h>
+
+// Forward Declarations
+
+namespace lldb {
+
+class SBAddress;
+class SBBlock;
+class SBBreakpoint;
+class SBBreakpointLocation;
+class SBBroadcaster;
+class SBCommandContext;
+class SBCommandInterpreter;
+class SBCommandReturnObject;
+class SBCommunication;
+class SBCompileUnit;
+class SBDebugger;
+class SBError;
+class SBEvent;
+class SBEventList;
+class SBFileSpec;
+class SBFrame;
+class SBFunction;
+class SBHostOS;
+class SBInputReader;
+class SBInstruction;
+class SBLineEntry;
+class SBListener;
+class SBModule;
+class SBProcess;
+class SBSourceManager;
+class SBSymbol;
+class SBSymbolContext;
+class SBStringList;
+class SBTarget;
+class SBThread;
+class SBValue;
+
+}
+
+#endif // LLDB_SBDefines_h_
diff --git a/lldb/include/lldb/API/SBError.h b/lldb/include/lldb/API/SBError.h
new file mode 100644
index 00000000000..1d23c736d2a
--- /dev/null
+++ b/lldb/include/lldb/API/SBError.h
@@ -0,0 +1,102 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBError {
+public:
+ SBError ();
+
+ SBError (const SBError &rhs);
+
+ ~SBError();
+
+#ifndef SWIG
+
+ const SBError &
+ operator =(const SBError &rhs);
+
+#endif
+
+ 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, ...);
+
+ bool
+ IsValid () const;
+
+protected:
+ friend class SBArguments;
+ friend class SBCommunication;
+ friend class SBHostOS;
+ friend class SBInputReader;
+ friend class SBProcess;
+
+#ifndef SWIG
+
+ lldb_private::Error *
+ get();
+
+ lldb_private::Error *
+ operator->();
+
+ const lldb_private::Error &
+ operator*() const;
+
+#endif
+
+
+ void
+ SetError (const lldb_private::Error &lldb_error);
+
+private:
+ std::auto_ptr<lldb_private::Error> m_lldb_object_ap;
+
+ void
+ CreateIfNeeded ();
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBError_h_
diff --git a/lldb/include/lldb/API/SBEvent.h b/lldb/include/lldb/API/SBEvent.h
new file mode 100644
index 00000000000..2267d8d4ce2
--- /dev/null
+++ b/lldb/include/lldb/API/SBEvent.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_SBEvent_h_
+#define LLDB_SBEvent_h_
+
+#include <vector>
+
+#include <LLDB/SBDefines.h>
+
+namespace lldb {
+
+class SBBroadcaster;
+
+class SBEvent
+{
+public:
+ SBEvent();
+
+ // Make an event that contains a C string.
+ SBEvent (uint32_t event, const char *cstr, uint32_t cstr_len);
+
+ ~SBEvent();
+
+ bool
+ IsValid() const;
+
+ void
+ Dump (FILE *f) const;
+
+ const char *
+ GetDataFlavor ();
+
+ uint32_t
+ GetType () const;
+
+ lldb::SBBroadcaster
+ GetBroadcaster () const;
+
+ bool
+ BroadcasterMatchesPtr (const lldb::SBBroadcaster *broadcaster);
+
+ bool
+ BroadcasterMatchesRef (const lldb::SBBroadcaster &broadcaster);
+
+ void
+ Clear();
+
+ static const char *
+ GetCStringFromEvent (const lldb::SBEvent &event);
+
+protected:
+ friend class SBListener;
+ friend class SBBroadcaster;
+ friend class SBDebugger;
+ friend class SBProcess;
+
+ SBEvent (lldb::EventSP &event_sp);
+
+ lldb::EventSP &
+ GetSharedPtr () const;
+
+ void
+ SetEventSP (lldb::EventSP &event_sp);
+
+ void
+ SetLLDBObjectPtr (lldb_private::Event* event);
+
+ lldb_private::Event *
+ GetLLDBObjectPtr ();
+
+ const lldb_private::Event *
+ GetLLDBObjectPtr () const;
+
+private:
+
+ mutable lldb::EventSP m_event_sp;
+ mutable lldb_private::Event *m_lldb_object;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBEvent_h_
diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h
new file mode 100644
index 00000000000..dd6718ec942
--- /dev/null
+++ b/lldb/include/lldb/API/SBFileSpec.h
@@ -0,0 +1,83 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBFileSpec
+{
+public:
+ SBFileSpec ();
+
+ SBFileSpec (const lldb::SBFileSpec &rhs);
+
+ SBFileSpec (const char *path);
+
+ ~SBFileSpec ();
+
+#ifndef SWIG
+ const SBFileSpec &
+ operator = (const lldb::SBFileSpec &rhs);
+#endif
+
+ bool
+ IsValid() const;
+
+ bool
+ Exists () const;
+
+ 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);
+
+private:
+ friend class SBLineEntry;
+ friend class SBCompileUnit;
+ friend class SBHostOS;
+ friend class SBModule;
+ friend class SBSourceManager;
+ friend class SBTarget;
+
+ void
+ SetFileSpec (const lldb_private::FileSpec& fs);
+#ifndef SWIG
+
+ const lldb_private::FileSpec *
+ operator->() const;
+
+ const lldb_private::FileSpec *
+ get() const;
+
+ const lldb_private::FileSpec &
+ operator*() const;
+
+ const lldb_private::FileSpec &
+ ref() const;
+
+#endif
+
+ std::auto_ptr <lldb_private::FileSpec> m_lldb_object_ap;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBFileSpec_h_
diff --git a/lldb/include/lldb/API/SBFrame.h b/lldb/include/lldb/API/SBFrame.h
new file mode 100644
index 00000000000..36106bdbff5
--- /dev/null
+++ b/lldb/include/lldb/API/SBFrame.h
@@ -0,0 +1,130 @@
+//===-- 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/SBDefines.h>
+#include <LLDB/SBValueList.h>
+
+namespace lldb {
+
+class SBValue;
+
+class SBFrame
+{
+public:
+ SBFrame ();
+
+ ~SBFrame();
+
+ 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::SBBlock
+ GetBlock () const;
+
+ lldb::SBLineEntry
+ GetLineEntry () const;
+
+ lldb::SBThread
+ GetThread () const;
+
+ const char *
+ Disassemble () const;
+
+ void
+ Clear();
+
+#ifndef SWIG
+ bool
+ operator == (const lldb::SBFrame &rhs) const;
+
+ bool
+ operator != (const lldb::SBFrame &rhs) const;
+
+#endif
+
+ lldb::SBValueList
+ GetVariables (bool arguments,
+ bool locals,
+ bool statics,
+ bool in_scope_only);
+
+ lldb::SBValueList
+ GetRegisters ();
+
+ lldb::SBValue
+ LookupVar (const char *var_name);
+
+ lldb::SBValue
+ LookupVarInScope (const char *var_name, const char *scope);
+
+protected:
+ friend class SBValue;
+
+ lldb_private::StackFrame *
+ GetLLDBObjectPtr ();
+
+private:
+ friend class SBThread;
+
+#ifndef SWIG
+
+ lldb_private::StackFrame *
+ operator->() const;
+
+ // Mimic shared pointer...
+ lldb_private::StackFrame *
+ get() const;
+
+#endif
+
+
+ SBFrame (const lldb::StackFrameSP &lldb_object_sp);
+
+ void
+ SetFrame (const lldb::StackFrameSP &lldb_object_sp);
+
+ lldb::StackFrameSP m_lldb_object_sp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBFrame_h_
diff --git a/lldb/include/lldb/API/SBFunction.h b/lldb/include/lldb/API/SBFunction.h
new file mode 100644
index 00000000000..613d8b0fe09
--- /dev/null
+++ b/lldb/include/lldb/API/SBFunction.h
@@ -0,0 +1,55 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBFunction
+{
+public:
+
+ SBFunction ();
+
+ ~SBFunction ();
+
+ bool
+ IsValid () const;
+
+ const char *
+ GetName() const;
+
+ const char *
+ GetMangledName () const;
+
+#ifndef SWIG
+ bool
+ operator == (const lldb::SBFunction &rhs) const;
+
+ bool
+ operator != (const lldb::SBFunction &rhs) const;
+#endif
+
+private:
+ friend class SBFrame;
+ friend class SBSymbolContext;
+
+ SBFunction (lldb_private::Function *lldb_object_ptr);
+
+
+ lldb_private::Function *m_lldb_object_ptr;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBFunction_h_
diff --git a/lldb/include/lldb/API/SBHostOS.h b/lldb/include/lldb/API/SBHostOS.h
new file mode 100644
index 00000000000..53943cac7a6
--- /dev/null
+++ b/lldb/include/lldb/API/SBHostOS.h
@@ -0,0 +1,54 @@
+//===-- 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/SBDefines.h>
+#include <LLDB/SBFileSpec.h>
+
+namespace lldb {
+
+class SBHostOS
+{
+public:
+
+ static lldb::SBFileSpec
+ GetProgramFileSpec ();
+
+ 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/lldb/include/lldb/API/SBInputReader.h b/lldb/include/lldb/API/SBInputReader.h
new file mode 100644
index 00000000000..5b2590e29b6
--- /dev/null
+++ b/lldb/include/lldb/API/SBInputReader.h
@@ -0,0 +1,100 @@
+//===-- 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/SBDefines.h>
+
+#include <termios.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 (Callback callback,
+ void *callback_baton,
+ lldb::InputReaderGranularity granularity,
+ const char *end_token,
+ const char *prompt,
+ bool echo);
+
+ bool
+ IsValid () const;
+
+#ifndef SWIG
+ const SBInputReader &
+ operator = (const lldb::SBInputReader &rhs);
+#endif
+
+ bool
+ IsActive () const;
+
+ bool
+ IsDone () const;
+
+ void
+ SetIsDone (bool value);
+
+ InputReaderGranularity
+ GetGranularity ();
+
+protected:
+ friend class SBDebugger;
+
+#ifndef SWIG
+
+ lldb_private::InputReader *
+ operator->() const;
+
+ lldb::InputReaderSP &
+ operator *();
+
+ const lldb::InputReaderSP &
+ operator *() const;
+#endif
+
+ lldb_private::InputReader *
+ get() 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_reader_sp;
+ Callback m_callback_function;
+ void *m_callback_baton;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBInputReader_h_
diff --git a/lldb/include/lldb/API/SBInstruction.h b/lldb/include/lldb/API/SBInstruction.h
new file mode 100644
index 00000000000..256b1c017b8
--- /dev/null
+++ b/lldb/include/lldb/API/SBInstruction.h
@@ -0,0 +1,57 @@
+//===-- 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/SBDefines.h>
+
+// There's a lot to be fixed here, but need to wait for underlying insn implementation
+// to be revised & settle down first.
+
+//class lldb_private::Disassembler::Instruction;
+
+namespace lldb {
+
+class SBInstruction
+{
+public:
+
+ //SBInstruction (lldb_private::Disassembler::Instruction *lldb_insn);
+
+ SBInstruction ();
+
+ ~SBInstruction ();
+
+ //bool
+ //IsValid();
+
+ //size_t
+ //GetByteSize ();
+
+ //void
+ //SetByteSize (size_t byte_size);
+
+ //bool
+ //DoesBranch ();
+
+ void
+ Print (FILE *out);
+
+private:
+
+ //lldb_private::Disassembler::Instruction::SharedPtr m_lldb_object_sp;
+
+
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBInstruction_h_
diff --git a/lldb/include/lldb/API/SBInstructionList.h b/lldb/include/lldb/API/SBInstructionList.h
new file mode 100644
index 00000000000..455807466fa
--- /dev/null
+++ b/lldb/include/lldb/API/SBInstructionList.h
@@ -0,0 +1,53 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBInstructionList
+{
+public:
+
+ SBInstructionList ();
+
+ ~SBInstructionList ();
+
+ size_t
+ GetSize ();
+
+ lldb::SBInstruction
+ GetInstructionAtIndex (uint32_t idx);
+
+ void
+ Clear ();
+
+ void
+ AppendInstruction (lldb::SBInstruction inst);
+
+
+ void
+ Print (FILE *out);
+
+private:
+
+ // If we have an instruction list, it will need to be backed by an
+ // lldb_private class that contains the list, we can't inherit from
+ // std::vector here...
+ //std::vector <SBInstruction> m_insn_list;
+
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBInstructionList_h_
diff --git a/lldb/include/lldb/API/SBLineEntry.h b/lldb/include/lldb/API/SBLineEntry.h
new file mode 100644
index 00000000000..2e18bb73cf1
--- /dev/null
+++ b/lldb/include/lldb/API/SBLineEntry.h
@@ -0,0 +1,88 @@
+//===-- 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/SBDefines.h>
+#include <LLDB/SBAddress.h>
+#include <LLDB/SBFileSpec.h>
+
+namespace lldb {
+
+class SBLineEntry
+{
+public:
+
+ SBLineEntry ();
+
+ SBLineEntry (const lldb::SBLineEntry &rhs);
+
+ ~SBLineEntry ();
+
+#ifndef SWIG
+ const lldb::SBLineEntry &
+ operator = (const lldb::SBLineEntry &rhs);
+#endif
+
+ lldb::SBAddress
+ GetStartAddress () const;
+
+ lldb::SBAddress
+ GetEndAddress () const;
+
+ bool
+ IsValid () const;
+
+ lldb::SBFileSpec
+ GetFileSpec () const;
+
+ uint32_t
+ GetLine () const;
+
+ uint32_t
+ GetColumn () const;
+
+#ifndef SWIG
+ bool
+ operator == (const lldb::SBLineEntry &rhs) const;
+
+ bool
+ operator != (const lldb::SBLineEntry &rhs) const;
+
+#endif
+
+private:
+ friend class SBCompileUnit;
+ friend class SBFrame;
+ friend class SBSymbolContext;
+
+#ifndef SWIG
+
+ const lldb_private::LineEntry *
+ operator->() const;
+
+ const lldb_private::LineEntry &
+ operator*() const;
+
+#endif
+
+
+ SBLineEntry (const lldb_private::LineEntry *lldb_object_ptr);
+
+ void
+ SetLineEntry (const lldb_private::LineEntry &lldb_object_ref);
+
+ std::auto_ptr<lldb_private::LineEntry> m_lldb_object_ap;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBLineEntry_h_
diff --git a/lldb/include/lldb/API/SBListener.h b/lldb/include/lldb/API/SBListener.h
new file mode 100644
index 00000000000..8fd28f7635f
--- /dev/null
+++ b/lldb/include/lldb/API/SBListener.h
@@ -0,0 +1,119 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBListener
+{
+public:
+ friend class SBBroadcaster;
+ friend class SBCommandInterpreter;
+ friend class SBDebugger;
+ friend class SBTarget;
+
+ SBListener (const char *name);
+
+ SBListener (lldb_private::Listener &listener);
+
+ SBListener ();
+
+ ~SBListener ();
+
+ void
+ AddEvent (const lldb::SBEvent &event);
+
+ void
+ Clear ();
+
+ bool
+ IsValid () const;
+
+ 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);
+
+private:
+
+#ifndef SWIG
+
+ lldb_private::Listener *
+ operator->() const;
+
+ lldb_private::Listener *
+ get() const;
+
+ lldb_private::Listener &
+ operator *();
+
+ const lldb_private::Listener &
+ operator *() const;
+
+#endif
+
+
+
+ lldb_private::Listener *m_lldb_object_ptr;
+ bool m_lldb_object_ptr_owned;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBListener_h_
diff --git a/lldb/include/lldb/API/SBModule.h b/lldb/include/lldb/API/SBModule.h
new file mode 100644
index 00000000000..13aa5931a14
--- /dev/null
+++ b/lldb/include/lldb/API/SBModule.h
@@ -0,0 +1,79 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBModule
+{
+public:
+
+ SBModule ();
+
+ ~SBModule ();
+
+ bool
+ IsValid () const;
+
+ lldb::SBFileSpec
+ GetFileSpec () const;
+
+ const uint8_t *
+ GetUUIDBytes () const;
+
+#ifndef SWIG
+ bool
+ operator == (const lldb::SBModule &rhs) const;
+
+ bool
+ operator != (const lldb::SBModule &rhs) const;
+
+#endif
+
+
+private:
+ friend class SBSymbolContext;
+ friend class SBTarget;
+ friend class SBFrame;
+
+ explicit SBModule (const lldb::ModuleSP& module_sp);
+
+ void
+ SetModule (const lldb::ModuleSP& module_sp);
+#ifndef SWIG
+
+ lldb::ModuleSP &
+ operator *();
+
+
+ lldb_private::Module *
+ operator ->();
+
+ const lldb_private::Module *
+ operator ->() const;
+
+ lldb_private::Module *
+ get();
+
+ const lldb_private::Module *
+ get() const;
+
+#endif
+
+ lldb::ModuleSP m_lldb_object_sp;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBModule_h_
diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h
new file mode 100644
index 00000000000..caba20447cd
--- /dev/null
+++ b/lldb/include/lldb/API/SBProcess.h
@@ -0,0 +1,195 @@
+//===-- 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/SBDefines.h>
+#include <LLDB/SBError.h>
+#include <LLDB/SBTarget.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),
+ };
+
+ SBProcess ();
+
+ SBProcess (const lldb::SBProcess& rhs);
+
+ ~SBProcess();
+
+ void
+ Clear ();
+
+ bool
+ IsValid() const;
+
+ lldb::SBTarget
+ GetTarget() 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;
+
+ void
+ ReportCurrentState (const lldb::SBEvent &event, FILE *out) const;
+
+ void
+ AppendCurrentStateReport (const lldb::SBEvent &event, lldb::SBCommandReturnObject &result);
+
+ //------------------------------------------------------------------
+ // Thread related functions
+ //------------------------------------------------------------------
+ uint32_t
+ GetNumThreads ();
+
+ lldb::SBThread
+ GetThreadAtIndex (size_t index);
+
+ lldb::SBThread
+ GetThreadByID (lldb::tid_t sb_thread_id);
+
+ lldb::SBThread
+ GetCurrentThread () const;
+
+ bool
+ SetCurrentThread (const lldb::SBThread &thread);
+
+ bool
+ SetCurrentThreadByID (uint32_t tid);
+
+ //------------------------------------------------------------------
+ // Stepping related functions
+ //------------------------------------------------------------------
+
+ lldb::StateType
+ GetState ();
+
+ int
+ GetExitStatus ();
+
+ const char *
+ GetExitDescription ();
+
+ lldb::pid_t
+ GetProcessID ();
+
+ uint32_t
+ GetAddressByteSize() const;
+
+ SBError
+ Destroy ();
+
+ void
+ DisplayThreadsInfo (FILE *out = NULL, FILE *err = NULL, bool only_threads_with_stop_reason = true);
+
+ void
+ ListThreads ();
+
+ bool
+ WaitUntilProcessHasStopped (lldb::SBCommandReturnObject &result);
+
+ lldb::pid_t
+ AttachByPID (lldb::pid_t pid); // DEPRECATED: will be removed in a few builds in favor of SBError AttachByPID(pid_t)
+
+ SBError
+ Attach (lldb::pid_t pid);
+
+ SBError
+ AttachByName (const char *name, bool wait_for_launch);
+
+ SBError
+ Continue ();
+
+ SBError
+ Stop ();
+
+ SBError
+ Kill ();
+
+ SBError
+ Detach ();
+
+ SBError
+ Signal (int signal);
+
+ void
+ Backtrace (bool all_threads = false, uint32_t num_frames = 0);
+
+ size_t
+ ReadMemory (addr_t addr, void *buf, size_t size, SBError &error);
+
+ size_t
+ WriteMemory (addr_t addr, const void *buf, size_t size, SBError &error);
+
+ // Events
+ static lldb::StateType
+ GetStateFromEvent (const lldb::SBEvent &event);
+
+ static bool
+ GetRestartedFromEvent (const lldb::SBEvent &event);
+
+ static lldb::SBProcess
+ GetProcessFromEvent (const lldb::SBEvent &event);
+
+ lldb::SBBroadcaster
+ GetBroadcaster () const;
+
+protected:
+ friend class SBAddress;
+ friend class SBBreakpoint;
+ friend class SBBreakpointLocation;
+ friend class SBCommandInterpreter;
+ friend class SBDebugger;
+ friend class SBTarget;
+ friend class SBThread;
+ friend class SBValue;
+
+#ifndef SWIG
+
+ lldb_private::Process *
+ operator->() const;
+
+ // Mimic shared pointer...
+ lldb_private::Process *
+ get() const;
+
+#endif
+
+
+ SBProcess (const lldb::ProcessSP &process_sp);
+
+ void
+ SetProcess (const lldb::ProcessSP &process_sp);
+
+ lldb::ProcessSP m_lldb_object_sp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBProcess_h_
diff --git a/lldb/include/lldb/API/SBSourceManager.h b/lldb/include/lldb/API/SBSourceManager.h
new file mode 100644
index 00000000000..54ac612ac2a
--- /dev/null
+++ b/lldb/include/lldb/API/SBSourceManager.h
@@ -0,0 +1,47 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBSourceManager
+{
+public:
+ ~SBSourceManager();
+
+ size_t
+ DisplaySourceLinesWithLineNumbers (const lldb::SBFileSpec &file,
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ const char* current_line_cstr,
+ FILE *f);
+
+
+protected:
+ friend class SBCommandInterpreter;
+ friend class SBDebugger;
+
+ SBSourceManager(lldb_private::SourceManager &source_manager);
+
+ lldb_private::SourceManager &
+ GetLLDBManager ();
+
+private:
+
+ lldb_private::SourceManager &m_source_manager;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBSourceManager_h_
diff --git a/lldb/include/lldb/API/SBStringList.h b/lldb/include/lldb/API/SBStringList.h
new file mode 100644
index 00000000000..2d1300fe183
--- /dev/null
+++ b/lldb/include/lldb/API/SBStringList.h
@@ -0,0 +1,72 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBStringList
+{
+public:
+
+ SBStringList ();
+
+ SBStringList (const lldb_private::StringList *lldb_strings);
+
+ SBStringList (const lldb::SBStringList &rhs);
+
+ ~SBStringList ();
+
+ bool
+ IsValid() const;
+
+ void
+ AppendString (const char *str);
+
+ void
+ AppendList (const char **strv, int strc);
+
+ void
+ AppendList (lldb::SBStringList strings);
+
+ uint32_t
+ GetSize () const;
+
+ const char *
+ GetStringAtIndex (size_t idx);
+
+ void
+ Clear ();
+
+#ifndef SWIG
+
+ const lldb_private::StringList *
+ operator->() const;
+
+ const lldb_private::StringList &
+ operator*() const;
+
+ const lldb::SBStringList &
+ operator = (const lldb::SBStringList &rhs);
+
+#endif
+
+private:
+
+ std::auto_ptr<lldb_private::StringList> m_lldb_object_ap;
+
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBStringList_h_
diff --git a/lldb/include/lldb/API/SBSymbol.h b/lldb/include/lldb/API/SBSymbol.h
new file mode 100644
index 00000000000..b7a3058d3c1
--- /dev/null
+++ b/lldb/include/lldb/API/SBSymbol.h
@@ -0,0 +1,55 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBSymbol
+{
+public:
+
+ SBSymbol ();
+
+ ~SBSymbol ();
+
+ bool
+ IsValid () const;
+
+
+ const char *
+ GetName() const;
+
+ const char *
+ GetMangledName () const;
+
+#ifndef SWIG
+ bool
+ operator == (const lldb::SBSymbol &rhs) const;
+
+ bool
+ operator != (const lldb::SBSymbol &rhs) const;
+#endif
+
+
+private:
+ friend class SBSymbolContext;
+
+ SBSymbol (lldb_private::Symbol *lldb_object_ptr);
+
+ lldb_private::Symbol *m_lldb_object_ptr;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBSymbol_h_
diff --git a/lldb/include/lldb/API/SBSymbolContext.h b/lldb/include/lldb/API/SBSymbolContext.h
new file mode 100644
index 00000000000..fd14511883e
--- /dev/null
+++ b/lldb/include/lldb/API/SBSymbolContext.h
@@ -0,0 +1,73 @@
+//===-- 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/SBDefines.h>
+#include <LLDB/SBBlock.h>
+#include <LLDB/SBCompileUnit.h>
+#include <LLDB/SBFunction.h>
+#include <LLDB/SBLineEntry.h>
+#include <LLDB/SBModule.h>
+#include <LLDB/SBSymbol.h>
+
+namespace lldb {
+
+class SBSymbolContext
+{
+public:
+ SBSymbolContext ();
+
+ SBSymbolContext (const lldb::SBSymbolContext& rhs);
+
+ ~SBSymbolContext ();
+
+ bool
+ IsValid () const;
+
+#ifndef SWIG
+ const lldb::SBSymbolContext &
+ operator = (const lldb::SBSymbolContext &rhs);
+#endif
+
+ SBModule GetModule ();
+ SBCompileUnit GetCompileUnit ();
+ SBFunction GetFunction ();
+ SBBlock GetBlock ();
+ SBLineEntry GetLineEntry ();
+ SBSymbol GetSymbol ();
+
+protected:
+ friend class SBFrame;
+ friend class SBThread;
+
+#ifndef SWIG
+
+ lldb_private::SymbolContext*
+ operator->() const;
+
+#endif
+
+ lldb_private::SymbolContext *
+ GetLLDBObjectPtr() const;
+
+ SBSymbolContext (const lldb_private::SymbolContext *sc_ptr);
+
+ void
+ SetSymbolContext (const lldb_private::SymbolContext *sc_ptr);
+
+private:
+ std::auto_ptr<lldb_private::SymbolContext> m_lldb_object_ap;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBSymbolContext_h_
diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
new file mode 100644
index 00000000000..e950b4cda43
--- /dev/null
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -0,0 +1,167 @@
+//===-- 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/SBDefines.h>
+#include <LLDB/SBBroadcaster.h>
+#include <LLDB/SBFileSpec.h>
+
+namespace lldb {
+
+class SBBreakpoint;
+
+class SBTarget
+{
+public:
+ //------------------------------------------------------------------
+ // Broadcaster bits.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitBreakpointChanged = (1 << 0),
+ eBroadcastBitModulesLoaded = (1 << 1),
+ eBroadcastBitModulesUnloaded = (1 << 2)
+ };
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SBTarget (const lldb::SBTarget& rhs);
+
+ SBTarget (); // Required for SWIG.
+
+ //------------------------------------------------------------------
+ // Destructor
+ //------------------------------------------------------------------
+ ~SBTarget();
+
+ const lldb::SBTarget&
+ Assign (const lldb::SBTarget& rhs);
+
+ bool
+ IsValid() const;
+
+ lldb::SBProcess
+ GetProcess ();
+
+ lldb::SBProcess
+ CreateProcess ();
+
+ lldb::SBProcess
+ LaunchProcess (char const **argv,
+ char const **envp,
+ const char *tty,
+ bool stop_at_entry);
+
+ lldb::SBFileSpec
+ GetExecutable ();
+
+ uint32_t
+ GetNumModules () const;
+
+ lldb::SBModule
+ GetModuleAtIndex (uint32_t idx);
+
+ lldb::SBModule
+ FindModule (const lldb::SBFileSpec &file_spec);
+
+ bool
+ DeleteTargetFromList (lldb_private::TargetList *list);
+
+ bool
+ MakeCurrentTarget ();
+
+ 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);
+
+ lldb::SBBreakpoint
+ BreakpointCreateByRegex (const char *symbol_name_regex, const char *module_name = NULL);
+
+ lldb::SBBreakpoint
+ BreakpointCreateByAddress (addr_t address);
+
+ bool
+ BreakpointDelete (break_id_t break_id);
+
+ void
+ ListAllBreakpoints ();
+
+ lldb::SBBreakpoint
+ FindBreakpointByID (break_id_t break_id);
+
+ bool
+ EnableAllBreakpoints ();
+
+ bool
+ DisableAllBreakpoints ();
+
+ bool
+ DeleteAllBreakpoints ();
+
+ lldb::SBBroadcaster
+ GetBroadcaster () const;
+
+ //void
+ //Disassemble ();
+
+ void
+ Disassemble (lldb::addr_t file_address_start, lldb::addr_t file_address_end = LLDB_INVALID_ADDRESS,
+ const char *module_name = NULL);
+
+ void
+ Disassemble (const char *function_name, const char *module_name = NULL);
+
+#ifndef SWIG
+ bool
+ operator == (const lldb::SBTarget &rhs) const;
+
+ bool
+ operator != (const lldb::SBTarget &rhs) const;
+
+#endif
+
+protected:
+ friend class SBDebugger;
+ friend class SBProcess;
+
+ //------------------------------------------------------------------
+ // Constructors are private, use static Target::Create function to
+ // create an instance of this class.
+ //------------------------------------------------------------------
+
+ SBTarget (const lldb::TargetSP& target_sp);
+
+ void
+ SetLLBDTarget (const lldb::TargetSP& target_sp);
+
+ lldb_private::Target *
+ GetLLDBObjectPtr();
+
+ const lldb_private::Target *
+ GetLLDBObjectPtr() const;
+
+private:
+ //------------------------------------------------------------------
+ // For Target only
+ //------------------------------------------------------------------
+
+ lldb::TargetSP m_target_sp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBTarget_h_
diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h
new file mode 100644
index 00000000000..220424fd87f
--- /dev/null
+++ b/lldb/include/lldb/API/SBThread.h
@@ -0,0 +1,152 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBFrame;
+
+class SBThread
+{
+public:
+ SBThread ();
+
+ SBThread (const lldb::SBThread &thread);
+
+ ~SBThread();
+
+ bool
+ IsValid() const;
+
+ lldb::StopReason
+ GetStopReason();
+
+ size_t
+ GetStopDescription (char *dst, size_t dst_len);
+
+ lldb::tid_t
+ GetThreadID () const;
+
+ uint32_t
+ GetIndexID () const;
+
+ const char *
+ GetName () const;
+
+ const char *
+ GetQueueName() const;
+
+ void
+ DisplayFramesForCurrentContext (FILE *out,
+ FILE *err,
+ uint32_t first_frame,
+ uint32_t num_frames,
+ bool show_frame_info,
+ uint32_t num_frames_with_source,
+ uint32_t source_lines_before = 3,
+ uint32_t source_lines_after = 3);
+
+ bool
+ DisplaySingleFrameForCurrentContext (FILE *out,
+ FILE *err,
+ lldb::SBFrame &frame,
+ bool show_frame_info,
+ bool show_source,
+ uint32_t source_lines_after,
+ uint32_t source_lines_before);
+
+ void
+ StepOver (lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping);
+
+ void
+ StepInto (lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping);
+
+ void
+ StepOut ();
+
+ void
+ StepInstruction(bool step_over);
+
+ void
+ RunToAddress (lldb::addr_t addr);
+
+ void
+ Backtrace (uint32_t num_frames = 0);
+
+ uint32_t
+ GetNumFrames ();
+
+ lldb::SBFrame
+ GetFrameAtIndex (uint32_t idx);
+
+ lldb::SBProcess
+ GetProcess ();
+
+#ifndef SWIG
+
+ const lldb::SBThread &
+ operator = (const lldb::SBThread &rhs);
+
+ bool
+ operator == (const lldb::SBThread &rhs) const;
+
+ bool
+ operator != (const lldb::SBThread &rhs) const;
+
+#endif
+
+
+protected:
+ friend class SBBreakpoint;
+ friend class SBBreakpointLocation;
+ friend class SBFrame;
+ friend class SBProcess;
+ friend class SBDebugger;
+ friend class SBValue;
+
+ lldb_private::Thread *
+ GetLLDBObjectPtr ();
+
+#ifndef SWIG
+
+ const lldb_private::Thread *
+ operator->() const;
+
+ const lldb_private::Thread &
+ operator*() const;
+
+
+ lldb_private::Thread *
+ operator->();
+
+ lldb_private::Thread &
+ operator*();
+
+#endif
+
+ SBThread (const lldb::ThreadSP& lldb_object_sp);
+
+ void
+ SetThread (const lldb::ThreadSP& lldb_object_sp);
+
+private:
+ //------------------------------------------------------------------
+ // Classes that inherit from Thread can see and modify these
+ //------------------------------------------------------------------
+
+ lldb::ThreadSP m_lldb_object_sp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBThread_h_
diff --git a/lldb/include/lldb/API/SBType.h b/lldb/include/lldb/API/SBType.h
new file mode 100644
index 00000000000..f647fbf20fc
--- /dev/null
+++ b/lldb/include/lldb/API/SBType.h
@@ -0,0 +1,31 @@
+//===-- 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/SBDefines.h>
+
+namespace lldb {
+
+class SBType
+{
+public:
+
+ static bool
+ IsPointerType (void *opaque_type);
+
+private:
+
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBType_h_
diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h
new file mode 100644
index 00000000000..395ca00a4f8
--- /dev/null
+++ b/lldb/include/lldb/API/SBValue.h
@@ -0,0 +1,126 @@
+//===-- 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/SBDefines.h>
+
+class lldb_private::Variable;
+class lldb_private::ValueObject;
+class lldb_private::ExecutionContext;
+
+namespace lldb {
+
+class SBValue
+{
+public:
+ SBValue ();
+
+ ~SBValue ();
+
+ bool
+ IsValid() const;
+
+ void
+ Print (FILE *out_file, lldb::SBFrame *frame, bool print_type, bool print_value);
+
+ const char *
+ GetName();
+
+ const char *
+ GetTypeName ();
+
+ size_t
+ GetByteSize ();
+
+ bool
+ IsInScope (const lldb::SBFrame &frame);
+
+ const char *
+ GetValue (const lldb::SBFrame &frame);
+
+ bool
+ GetValueDidChange ();
+
+ const char *
+ GetSummary (const lldb::SBFrame &frame);
+
+ const char *
+ GetLocation (const lldb::SBFrame &frame);
+
+ bool
+ SetValueFromCString (const lldb::SBFrame &frame, const char *value_str);
+
+ lldb::SBValue
+ GetChildAtIndex (uint32_t idx);
+
+ // 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);
+
+ uint32_t
+ GetNumChildren ();
+
+ bool
+ ValueIsStale ();
+
+ void *
+ GetOpaqueType();
+
+ //void
+ //DumpType ();
+
+ lldb::SBValue
+ Dereference ();
+
+ bool
+ TypeIsPtrType ();
+
+
+protected:
+ friend class SBValueList;
+ friend class SBFrame;
+
+ SBValue (const lldb::ValueObjectSP &value_sp);
+
+#ifndef SWIG
+
+ // Mimic shared pointer...
+ lldb_private::ValueObject *
+ get() const;
+
+ lldb_private::ValueObject *
+ operator->() const;
+
+ lldb::ValueObjectSP &
+ operator*();
+
+ const lldb::ValueObjectSP &
+ operator*() const;
+
+#endif
+
+private:
+
+ lldb_private::ExecutionContext
+ GetCurrentExecutionContext ();
+
+ lldb::ValueObjectSP m_lldb_object_sp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBValue_h_
diff --git a/lldb/include/lldb/API/SBValueList.h b/lldb/include/lldb/API/SBValueList.h
new file mode 100644
index 00000000000..49b5fef10c7
--- /dev/null
+++ b/lldb/include/lldb/API/SBValueList.h
@@ -0,0 +1,79 @@
+//===-- 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/SBDefines.h>
+
+class lldb_private::ValueObjectList;
+
+namespace lldb {
+
+class SBValueList
+{
+public:
+
+ SBValueList ();
+
+ SBValueList (const lldb::SBValueList &rhs);
+
+ ~SBValueList();
+
+ bool
+ IsValid() const;
+
+ void
+ Append (const lldb::SBValue &val_obj);
+
+ uint32_t
+ GetSize() const;
+
+ lldb::SBValue
+ GetValueAtIndex (uint32_t idx) const;
+
+ lldb::SBValue
+ FindValueObjectByUID (lldb::user_id_t uid);
+
+
+#ifndef SWIG
+ const lldb::SBValueList &
+ operator = (const lldb::SBValueList &rhs);
+
+ lldb_private::ValueObjectList *
+ operator -> ();
+
+ lldb_private::ValueObjectList &
+ operator* ();
+
+ const lldb_private::ValueObjectList *
+ operator -> () const;
+
+ const lldb_private::ValueObjectList &
+ operator* () const;
+#endif
+
+private:
+ friend class SBFrame;
+
+ SBValueList (const lldb_private::ValueObjectList *lldb_object_ptr);
+
+ void
+ Append (lldb::ValueObjectSP& val_obj_sp);
+
+ void
+ CreateIfNeeded ();
+
+ std::auto_ptr<lldb_private::ValueObjectList> m_lldb_object_ap;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBValueList_h_
diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h
new file mode 100644
index 00000000000..1f08636b54e
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/Breakpoint.h
@@ -0,0 +1,511 @@
+//===-- 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 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;
+
+
+ enum EventSubType
+ {
+ eBreakpointInvalidType = (1 << 0),
+ eBreakpointAdded = (1 << 1),
+ eBreakpointRemoved = (1 << 2),
+ eBreakpointLocationsAdded = (1 << 3),
+ eBreakpointLocationsRemoved = (1 << 4),
+ eBreakpointLocationResolved = (1 << 5)
+ };
+
+ BreakpointEventData (EventSubType sub_type,
+ lldb::BreakpointSP &new_breakpoint_sp);
+
+ virtual
+ ~BreakpointEventData();
+
+ EventSubType
+ GetSubType () const;
+
+ lldb::BreakpointSP &
+ GetBreakpoint ();
+
+
+ virtual void
+ Dump (Stream *s) const;
+
+ static BreakpointEventData *
+ GetEventDataFromEvent (const lldb::EventSP &event_sp);
+
+ static EventSubType
+ GetSubTypeFromEvent (const lldb::EventSP &event_sp);
+
+ static lldb::BreakpointSP
+ GetBreakpointFromEvent (const lldb::EventSP &event_sp);
+
+ private:
+ EventSubType m_sub_type;
+ 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] changedModules
+ /// The list of modules to look in for new locations.
+ //------------------------------------------------------------------
+ void
+ ResolveBreakpointInModules (ModuleList &changedModules);
+
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ void
+ ModulesChanged (ModuleList &changedModules,
+ bool load_event);
+
+
+ //------------------------------------------------------------------
+ // 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 (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 (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 (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 (uint32_t index);
+
+
+ const lldb::BreakpointSP
+ GetSP ();
+
+ //------------------------------------------------------------------
+ // 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 (int32_t count);
+
+ //------------------------------------------------------------------
+ /// Return the current Ignore Count.
+ /// @return
+ /// The number of breakpoint hits to be ignored.
+ //------------------------------------------------------------------
+ int32_t
+ GetIgnoreCount () 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 ();
+
+ //------------------------------------------------------------------
+ /// 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] baton
+ /// A void * pointer that will get passed back to the callback function.
+ //------------------------------------------------------------------
+ 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 condition expression to be checked when the breakpoint is hit.
+ /// @param[in] expression
+ /// The method that will get called when the breakpoint is hit.
+ //------------------------------------------------------------------
+ void
+ SetCondition (void *expression);
+
+ //------------------------------------------------------------------
+ // 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);
+
+ //------------------------------------------------------------------
+ /// Accessor for the breakpoint Target.
+ /// @return
+ /// This breakpoint's Target.
+ //------------------------------------------------------------------
+ Target &
+ GetTarget ();
+
+ const Target &
+ GetTarget () const;
+
+ void
+ GetResolverDescription (Stream *s);
+
+ 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 ();
+
+
+protected:
+ friend class Target;
+ friend class BreakpointLocation; // To call InvokeCallback
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ // Protected Methods
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// 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:
+
+ //------------------------------------------------------------------
+ /// Returns the shared pointer that this breakpoint holds for the
+ /// breakpoint location passed in as \a bp_loc_ptr. Passing in a
+ /// breakpoint location that doesn't belong to this breakpoint will
+ /// cause an assert.
+ ///
+ /// Meant to be used by the BreakpointLocation::GetSP() function.
+ ///
+ /// @return
+ /// A copy of the shared pointer for the given location.
+ //------------------------------------------------------------------
+ lldb::BreakpointLocationSP
+ GetLocationSP (BreakpointLocation *bp_loc_ptr);
+
+private:
+ //------------------------------------------------------------------
+ // For Breakpoint only
+ //------------------------------------------------------------------
+ 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.
+
+ DISALLOW_COPY_AND_ASSIGN(Breakpoint);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Breakpoint_h_
diff --git a/lldb/include/lldb/Breakpoint/BreakpointID.h b/lldb/include/lldb/Breakpoint/BreakpointID.h
new file mode 100644
index 00000000000..9e352100b9e
--- /dev/null
+++ b/lldb/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/lldb/include/lldb/Breakpoint/BreakpointIDList.h b/lldb/include/lldb/Breakpoint/BreakpointIDList.h
new file mode 100644
index 00000000000..bc88087616d
--- /dev/null
+++ b/lldb/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 ();
+
+ int
+ Size();
+
+ BreakpointID &
+ GetBreakpointIDAtIndex (int index);
+
+ bool
+ RemoveBreakpointIDAtIndex (int index);
+
+ void
+ Clear();
+
+ bool
+ AddBreakpointID (BreakpointID bp_id);
+
+ bool
+ AddBreakpointID (const char *bp_id);
+
+ bool
+ FindBreakpointID (BreakpointID &bp_id, int *position);
+
+ bool
+ FindBreakpointID (const char *bp_id, int *position);
+
+ void
+ InsertStringArray (const char **string_array, int array_size, CommandReturnObject &result);
+
+ static bool
+ StringContainsIDRangeExpression (const char *in_string, int *range_start_len, int *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/lldb/include/lldb/Breakpoint/BreakpointList.h b/lldb/include/lldb/Breakpoint/BreakpointList.h
new file mode 100644
index 00000000000..225bb3ba498
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/BreakpointList.h
@@ -0,0 +1,177 @@
+//===-- 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.
+ //------------------------------------------------------------------
+ virtual lldb::break_id_t
+ Add (lldb::BreakpointSP& bp_sp);
+
+ //------------------------------------------------------------------
+ /// 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
+ GetBreakpointByIndex (uint32_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
+ GetBreakpointByIndex (uint32_t i) const;
+
+ //------------------------------------------------------------------
+ /// Returns the number of elements in this breakpoint list.
+ ///
+ /// @result
+ /// The number of elements.
+ //------------------------------------------------------------------
+ size_t
+ GetSize() const { 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);
+
+ void
+ SetEnabledAll (bool enabled);
+
+ //------------------------------------------------------------------
+ /// Removes all the breakpoints from this list.
+ //------------------------------------------------------------------
+ void
+ RemoveAll ();
+
+ //------------------------------------------------------------------
+ /// 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
+ ClearAllBreakpointSites ();
+
+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/lldb/include/lldb/Breakpoint/BreakpointLocation.h b/lldb/include/lldb/Breakpoint/BreakpointLocation.h
new file mode 100644
index 00000000000..d51184d8760
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/BreakpointLocation.h
@@ -0,0 +1,354 @@
+//===-- 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>
+#include <memory>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Breakpoint/StoppointLocation.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointOptions.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/StringList.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 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 ();
+
+ //------------------------------------------------------------------
+ /// 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 ();
+
+ //------------------------------------------------------------------
+ /// Return the current Ignore Count.
+ ///
+ /// @return
+ /// The number of breakpoint hits to be ignored.
+ //------------------------------------------------------------------
+ int32_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 (int32_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 condition expression to be checked when the breakpoint is hit.
+ ///
+ /// @param[in] expression
+ /// The method that will get called when the breakpoint is hit.
+ //------------------------------------------------------------------
+ void
+ SetCondition (void *condition);
+
+
+ //------------------------------------------------------------------
+ /// 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 ();
+
+ //------------------------------------------------------------------
+ // 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;
+
+ //------------------------------------------------------------------
+ // 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 location specific breakpoint options.
+ ///
+ /// @return
+ /// A pointer to the containing breakpoint's options if this
+ /// location doesn't have its own copy.
+ //------------------------------------------------------------------
+ BreakpointOptions *
+ GetOptionsNoCopy ();
+
+protected:
+ friend class Breakpoint;
+ friend class CommandObjectBreakpointCommandAdd;
+ friend class Process;
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// 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);
+
+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,
+ Address &addr,
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID,
+ bool hardware = false);
+
+ //------------------------------------------------------------------
+ // Data members:
+ //------------------------------------------------------------------
+ Address m_address; ///< The address defining this location.
+ Breakpoint &m_owner; ///< The breakpoint that produced this object.
+ std::auto_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.)
+
+ DISALLOW_COPY_AND_ASSIGN (BreakpointLocation);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointLocation_h_
diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h b/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h
new file mode 100644
index 00000000000..9e04a2c4277
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h
@@ -0,0 +1,187 @@
+//===-- 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::user_id_t break_id, lldb::user_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::user_id_t break_id, lldb::user_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::user_id_t break_id, lldb::user_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 (uint32_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 (uint32_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);
+
+
+
+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::user_id_t break_id, lldb::user_id_t break_loc_id);
+
+ collection::const_iterator
+ GetIDPairConstIterator(lldb::user_id_t break_id, lldb::user_id_t break_loc_id) const;
+
+ collection m_break_loc_collection;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointLocationCollection_h_
diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocationList.h b/lldb/include/lldb/Breakpoint/BreakpointLocationList.h
new file mode 100644
index 00000000000..5c1c8ff5114
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/BreakpointLocationList.h
@@ -0,0 +1,285 @@
+//===-- 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:
+ ~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 (Address &addr) const;
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint location with id \a
+ /// breakID.
+ ///
+ /// @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::user_id_t breakID);
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ const lldb::BreakpointLocationSP
+ FindByID (lldb::user_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::user_id_t
+ FindIDByAddress (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 (uint32_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 (uint32_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;
+
+ //------------------------------------------------------------------
+ /// Removes the breakpoint location given by \b breakID from this
+ /// list.
+ ///
+ /// @param[in] breakID
+ /// The breakpoint location index to remove.
+ ///
+ /// @result
+ /// \b true if the breakpoint \a breakID was in the list.
+ //------------------------------------------------------------------
+ bool
+ Remove (lldb::user_id_t breakID);
+
+ //------------------------------------------------------------------
+ /// 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::user_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();
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ virtual lldb::user_id_t
+ Add (lldb::BreakpointLocationSP& bp_loc_sp);
+
+ typedef std::vector<lldb::BreakpointLocationSP> collection;
+ typedef std::map<lldb_private::Address,
+ lldb::BreakpointLocationSP,
+ Address::ModulePointerAndOffsetLessThanFunctionObject> addr_map;
+
+ // The breakpoint locations are stored in their Parent Breakpoint's location list by an
+ // index that is unique to this list, and not across all breakpoint location lists.
+ // This is only set in the Breakpoint's AddLocation method.
+ // There is another breakpoint location list, the owner's list in the BreakpointSite,
+ // but that should not reset the ID. Unfortunately UserID's SetID method is public.
+ lldb::break_id_t
+ GetNextID();
+
+ collection::iterator
+ GetIDIterator(lldb::user_id_t breakID);
+
+ collection::const_iterator
+ GetIDConstIterator(lldb::user_id_t breakID) const;
+
+ collection m_locations;
+ addr_map m_address_to_location;
+ mutable Mutex m_mutex;
+ lldb::break_id_t m_next_id;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointLocationList_h_
diff --git a/lldb/include/lldb/Breakpoint/BreakpointOptions.h b/lldb/include/lldb/Breakpoint/BreakpointOptions.h
new file mode 100644
index 00000000000..e7a3e3bf1d2
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/BreakpointOptions.h
@@ -0,0 +1,210 @@
+//===-- 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);
+
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ virtual ~BreakpointOptions();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const BreakpointOptions&
+ operator=(const BreakpointOptions& rhs);
+
+ //------------------------------------------------------------------
+ // Callbacks
+ //------------------------------------------------------------------
+ void SetCallback (BreakpointHitCallback callback, const lldb::BatonSP &baton_sp, bool synchronous = false);
+ bool InvokeCallback (StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+ bool IsCallbackSynchronous () {
+ return m_callback_is_synchronous;
+ };
+ Baton *GetBaton ();
+ void ClearCallback ();
+
+ //------------------------------------------------------------------
+ // Enabled/Ignore Count
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Check the Enable/Disable state.
+ /// @return
+ /// \b true if the breakpoint is enabled, \b false if disabled.
+ //------------------------------------------------------------------
+ bool
+ IsEnabled () const;
+
+ //------------------------------------------------------------------
+ /// If \a enable is \b true, enable the breakpoint, if \b false disable it.
+ //------------------------------------------------------------------
+ void
+ SetEnabled (bool enabled);
+
+ void
+ SetIgnoreCount (int32_t n);
+
+ //------------------------------------------------------------------
+ /// Return the current Ignore Count.
+ /// @return
+ /// The number of breakpoint hits to be ignored.
+ //------------------------------------------------------------------
+ int32_t
+ GetIgnoreCount () const;
+
+ //------------------------------------------------------------------
+ /// Set the breakpoint to ignore the next \a count breakpoint hits.
+ /// @param[in] count
+ /// The number of breakpoint hits to ignore.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// 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;
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// 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()
+ {
+ }
+
+ ~CommandData ()
+ {
+ }
+
+ StringList user_source;
+ StringList script_source;
+ };
+
+ 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;
+ int32_t m_ignore_count; // Number of times to ignore this breakpoint
+ lldb::tid_t m_thread_id; // Thread for which this breakpoint will take
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointOptions_h_
diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolver.h b/lldb/include/lldb/Breakpoint/BreakpointResolver.h
new file mode 100644
index 00000000000..1b1284f7970
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/BreakpointResolver.h
@@ -0,0 +1,123 @@
+//===-- 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/Core/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.
+ ///
+ /// @result
+ /// Returns breakpoint location id.
+ //------------------------------------------------------------------
+ BreakpointResolver (Breakpoint *bkpt);
+
+ //------------------------------------------------------------------
+ /// 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;
+
+protected:
+ Target *m_target; // Every resolver has a target.
+ Breakpoint *m_breakpoint; // This is the breakpoint we add locations to.
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(BreakpointResolver);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointResolver_h_
diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h b/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h
new file mode 100644
index 00000000000..6807bc0d8df
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h
@@ -0,0 +1,68 @@
+//===-- 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;
+
+protected:
+ Address m_addr;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(BreakpointResolverAddress);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointResolverAddress_h_
diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h b/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h
new file mode 100644
index 00000000000..285ef525f9f
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h
@@ -0,0 +1,65 @@
+//===-- 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);
+
+ 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;
+
+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(BreakpointResolverFileLine);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointResolverFileLine_h_
diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverName.h b/lldb/include/lldb/Breakpoint/BreakpointResolverName.h
new file mode 100644
index 00000000000..63e6b86837a
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/BreakpointResolverName.h
@@ -0,0 +1,75 @@
+//===-- 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
+// 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 *func_name,
+ Breakpoint::MatchType type = Breakpoint::Exact);
+
+ // Creates a function breakpoint by regular expression. Takes over control of the lifespan of func_regex.
+ BreakpointResolverName (Breakpoint *bkpt,
+ RegularExpression &func_regex);
+
+ BreakpointResolverName (Breakpoint *bkpt,
+ const char *class_name,
+ const char *method,
+ Breakpoint::MatchType type);
+
+ 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;
+
+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;
+ Breakpoint::MatchType m_match_type;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(BreakpointResolverName);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointResolverName_h_
diff --git a/lldb/include/lldb/Breakpoint/BreakpointSite.h b/lldb/include/lldb/Breakpoint/BreakpointSite.h
new file mode 100644
index 00000000000..aeb385ba18e
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/BreakpointSite.h
@@ -0,0 +1,258 @@
+//===-- 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 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,
+ size_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 (lldb::BreakpointLocationSP &owner);
+
+ //------------------------------------------------------------------
+ /// This method returns the number of breakpoint locations currently
+ /// located at this breakpoint site.
+ ///
+ /// @return
+ /// The number of owners.
+ //------------------------------------------------------------------
+ uint32_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 (uint32_t index);
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ bool
+ IsBreakpointAtThisSite (lldb::break_id_t bp_id);
+
+ 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.
+ //------------------------------------------------------------------
+ uint32_t
+ RemoveOwner (lldb::user_id_t break_id,
+ lldb::user_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,
+ lldb::BreakpointLocationSP& owner,
+ lldb::addr_t m_addr,
+ lldb::tid_t tid,
+ bool use_hardware);
+
+ DISALLOW_COPY_AND_ASSIGN(BreakpointSite);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointSite_h_
diff --git a/lldb/include/lldb/Breakpoint/BreakpointSiteList.h b/lldb/include/lldb/Breakpoint/BreakpointSiteList.h
new file mode 100644
index 00000000000..bfa8c51e3e8
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/BreakpointSiteList.h
@@ -0,0 +1,217 @@
+//===-- 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"
+
+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::user_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::user_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::user_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::user_id_t
+ FindIDByAddress (lldb::addr_t addr);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint site with index \a i.
+ ///
+ /// @param[in] i
+ /// The breakpoint site index to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint site. May contain a NULL pointer if the
+ /// breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ lldb::BreakpointSiteSP
+ GetByIndex (uint32_t i);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint site with index \a i - const version.
+ ///
+ /// @param[in] i
+ /// The breakpoint site index 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
+ GetByIndex (uint32_t i) const;
+
+ //------------------------------------------------------------------
+ /// 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::user_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);
+
+ void
+ SetEnabledForAll(const bool enable, const lldb::user_id_t except_id = LLDB_INVALID_BREAK_ID);
+
+ 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::user_id_t breakID);
+
+ //------------------------------------------------------------------
+ /// Returns the number of elements in the list.
+ ///
+ /// @result
+ /// The number of elements.
+ //------------------------------------------------------------------
+ size_t
+ GetSize() const { return m_bp_site_list.size(); }
+
+protected:
+ typedef std::map<lldb::addr_t, lldb::BreakpointSiteSP> collection;
+
+ collection::iterator
+ GetIDIterator(lldb::user_id_t breakID);
+
+ collection::const_iterator
+ GetIDConstIterator(lldb::user_id_t breakID) const;
+
+ // This function exposes the m_bp_site_list. I use the in Process because there
+ // are places there where you want to iterate over the list, and it is less efficient
+ // to do it by index. FIXME: Find a better way to do this.
+
+ const collection *
+ GetMap ();
+
+ collection m_bp_site_list; // The breakpoint site list.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointSiteList_h_
diff --git a/lldb/include/lldb/Breakpoint/Stoppoint.h b/lldb/include/lldb/Breakpoint/Stoppoint.h
new file mode 100644
index 00000000000..c294830f15e
--- /dev/null
+++ b/lldb/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/lldb/include/lldb/Breakpoint/StoppointCallbackContext.h b/lldb/include/lldb/Breakpoint/StoppointCallbackContext.h
new file mode 100644
index 00000000000..f2a6401e748
--- /dev/null
+++ b/lldb/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, Process* process, Thread *thread = NULL, StackFrame * frame = NULL, 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
+ ExecutionContext context; // 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/lldb/include/lldb/Breakpoint/StoppointLocation.h b/lldb/include/lldb/Breakpoint/StoppointLocation.h
new file mode 100644
index 00000000000..b52551005a6
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/StoppointLocation.h
@@ -0,0 +1,111 @@
+//===-- 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,
+ lldb::tid_t tid,
+ bool hardware);
+
+ StoppointLocation (lldb::break_id_t bid,
+ lldb::addr_t m_addr,
+ lldb::tid_t tid,
+ size_t size,
+ bool hardware);
+
+ virtual
+ ~StoppointLocation ();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ // Methods
+ //------------------------------------------------------------------
+ virtual lldb::addr_t
+ GetLoadAddress () const;
+
+ size_t
+ GetByteSize () const;
+
+ uint32_t
+ GetHitCount () const;
+
+ void
+ IncrementHitCount ();
+
+ uint32_t
+ GetHardwareIndex () const;
+
+ lldb::tid_t
+ GetThreadID() const;
+
+ bool
+ HardwarePreferred () const;
+
+ bool
+ IsHardware () const;
+
+ virtual bool
+ ShouldStop (StoppointCallbackContext *context);
+
+ virtual void
+ Dump (Stream *stream) const;
+
+ void
+ SetHardwareIndex (uint32_t index);
+
+ lldb::break_id_t
+ GetID () const;
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from StoppointLocation can see and modify these
+ //------------------------------------------------------------------
+ lldb::break_id_t m_loc_id; // Break ID
+ lldb::tid_t m_tid; // The thread ID if this stoppoint location is thread specific, or LLDB_INVALID_THREAD_ID if not thread specific.
+ 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 has been hit
+
+private:
+ //------------------------------------------------------------------
+ // For StoppointLocation only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN(StoppointLocation);
+ StoppointLocation(); // Disallow default constructor
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StoppointLocation_h_
diff --git a/lldb/include/lldb/Breakpoint/WatchpointLocation.h b/lldb/include/lldb/Breakpoint/WatchpointLocation.h
new file mode 100644
index 00000000000..9bf559d7166
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/WatchpointLocation.h
@@ -0,0 +1,69 @@
+//===-- WatchpointLocation.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_WatchpointLocation_h_
+#define liblldb_WatchpointLocation_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"
+
+namespace lldb_private {
+
+class WatchpointLocation :
+ public StoppointLocation
+{
+public:
+
+ WatchpointLocation (lldb::addr_t m_addr, lldb::tid_t tid, bool hardware);
+
+ ~WatchpointLocation ();
+
+ bool
+ IsEnabled () const;
+
+ void
+ SetEnabled (uint32_t enabled);
+
+ bool WatchpointRead () const;
+ bool WatchpointWrite () const;
+ int32_t GetIgnoreCount () const;
+ void SetIgnoreCount (int32_t n);
+ void SetWatchpointType (uint32_t type);
+ bool BreakpointWasHit (StoppointCallbackContext *context);
+ bool SetCallback (WatchpointHitCallback callback, void *callback_baton);
+ void Dump (Stream *s) const;
+
+private:
+ bool m_enabled; // Is this breakpoint enabled
+ 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
+ int32_t m_ignore_count; // Number of times to ignore this breakpoint
+ WatchpointHitCallback m_callback;
+ void * m_callback_baton; // Callback user data to pass to callback
+
+ static lldb::break_id_t
+ GetNextID();
+
+ DISALLOW_COPY_AND_ASSIGN (WatchpointLocation);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_WatchpointLocation_h_
diff --git a/lldb/include/lldb/Core/Address.h b/lldb/include/lldb/Core/Address.h
new file mode 100644
index 00000000000..14991085ec8
--- /dev/null
+++ b/lldb/include/lldb/Core/Address.h
@@ -0,0 +1,425 @@
+//===-- 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
+// 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 SymbolContextScope
+{
+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 name that an address resolves to
+ } DumpStyle;
+
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Initialize with a invalid section (NULL) and an invalid
+ /// offset (LLDB_INVALID_ADDRESS).
+ //------------------------------------------------------------------
+ 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);
+
+ //------------------------------------------------------------------
+ /// 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 Section* section, lldb::addr_t offset);
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~Address ();
+
+ //------------------------------------------------------------------
+ /// 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 ();
+
+ //------------------------------------------------------------------
+ /// 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, Process *process);
+
+ 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) 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 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 (Process *process) 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;
+
+ //------------------------------------------------------------------
+ /// 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;
+
+ //------------------------------------------------------------------
+ /// 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;
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ bool
+ IsLinkedAddress () const;
+
+ void
+ ResolveLinkedAddress ();
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ Module *
+ 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.
+ //------------------------------------------------------------------
+ const Section*
+ GetSection() const;
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// 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 Section* section);
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ void
+ CalculateSymbolContext (SymbolContext *sc);
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::DumpSymbolContext(Stream*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ void
+ DumpSymbolContext (Stream *s);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ const Section* m_section; ///< The section for the address, can be NULL.
+ lldb::addr_t m_offset; ///< Offset into section if \a m_section != NULL, else the absolute address value.
+};
+
+//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);
+bool operator== (const Address& lhs, const Address& rhs);
+bool operator!= (const Address& lhs, const Address& rhs);
+
+//Stream& operator << (Stream& strm, const Address& so_addr);
+
+} // namespace lldb_private
+
+#endif // liblldb_Address_h_
diff --git a/lldb/include/lldb/Core/AddressRange.h b/lldb/include/lldb/Core/AddressRange.h
new file mode 100644
index 00000000000..2d890327150
--- /dev/null
+++ b/lldb/include/lldb/Core/AddressRange.h
@@ -0,0 +1,280 @@
+//===-- 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 Section* 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, Process *process) 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, Process *process) 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, Process *process, 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();
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the base address of the range.
+ ///
+ /// @return
+ /// A const reference to the base address object.
+ //------------------------------------------------------------------
+ const Address &
+ GetBaseAddress() const;
+
+ //------------------------------------------------------------------
+ /// Get accessor for the byte size of this range.
+ ///
+ /// @return
+ /// The size in bytes of this address range.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetByteSize () const;
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ //------------------------------------------------------------------
+ size_t
+ MemorySize () const;
+
+ //------------------------------------------------------------------
+ /// 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);
+
+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/lldb/include/lldb/Core/AddressResolver.h b/lldb/include/lldb/Core/AddressResolver.h
new file mode 100644
index 00000000000..3690e7267f7
--- /dev/null
+++ b/lldb/include/lldb/Core/AddressResolver.h
@@ -0,0 +1,90 @@
+//===-- 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/Core/FileSpec.h"
+#include "lldb/Core/RegularExpression.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/lldb/include/lldb/Core/AddressResolverFileLine.h b/lldb/include/lldb/Core/AddressResolverFileLine.h
new file mode 100644
index 00000000000..ddeb0e0301d
--- /dev/null
+++ b/lldb/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/lldb/include/lldb/Core/AddressResolverName.h b/lldb/include/lldb/Core/AddressResolverName.h
new file mode 100644
index 00000000000..4ab352939ea
--- /dev/null
+++ b/lldb/include/lldb/Core/AddressResolverName.h
@@ -0,0 +1,67 @@
+//===-- 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"
+
+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/lldb/include/lldb/Core/ArchSpec.h b/lldb/include/lldb/Core/ArchSpec.h
new file mode 100644
index 00000000000..71b63f6b5b7
--- /dev/null
+++ b/lldb/include/lldb/Core/ArchSpec.h
@@ -0,0 +1,326 @@
+//===-- 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"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @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, or a
+/// string representation. 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:
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Default constructor that initializes the object with invalid
+ /// cpu type and subtype values.
+ //------------------------------------------------------------------
+ ArchSpec ();
+
+ //------------------------------------------------------------------
+ /// Constructor with cpu type and subtype.
+ ///
+ /// Constructor that initializes the object with supplied cpu and
+ /// subtypes.
+ //------------------------------------------------------------------
+ ArchSpec (uint32_t cpu, uint32_t sub);
+
+ //------------------------------------------------------------------
+ /// Construct with architecture name.
+ ///
+ /// Constructor that initializes the object with supplied
+ /// architecture name. There are also predefined values in
+ /// Defines.h:
+ /// @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 32 bit arch the current system defaults to (if any)
+ ///
+ /// @li \c LLDB_ARCH_DEFAULT_32BIT
+ /// The 64 bit arch the current system defaults to (if any)
+ //------------------------------------------------------------------
+ ArchSpec (const char *arch_name);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual in case this class is subclassed.
+ //------------------------------------------------------------------
+ virtual
+ ~ArchSpec ();
+
+ //------------------------------------------------------------------
+ /// Assignment operator.
+ ///
+ /// @param[in] rhs another ArchSpec object to copy.
+ ///
+ /// @return a const reference to this object
+ //------------------------------------------------------------------
+ const ArchSpec&
+ operator= (const ArchSpec& rhs);
+
+ //------------------------------------------------------------------
+ /// Get a string representation of the contained architecture.
+ ///
+ /// Gets a C string representation of the current architecture.
+ /// If the returned string is a valid architecture name, the string
+ /// came from a constant string values that do not need to be freed.
+ /// If the returned string uses the "N.M" format, the string comes
+ /// from a static buffer that should be copied.
+ ///
+ /// @return a NULL terminated C string that does not need to be
+ /// freed.
+ //------------------------------------------------------------------
+ const char *
+ AsCString () const;
+
+ //------------------------------------------------------------------
+ /// Returns a string representation of the supplied architecture.
+ ///
+ /// Class function to get a C string representation given a CPU type
+ /// and subtype.
+ ///
+ /// @param[in] cpu The cpu type of the architecture.
+ /// @param[in] subtype The cpu subtype of the architecture.
+ ///
+ /// @return a NULL terminated C string that does not need to be
+ /// freed.
+ //------------------------------------------------------------------
+ static const char *
+ AsCString (uint32_t cpu, uint32_t subtype);
+
+ //------------------------------------------------------------------
+ /// 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;
+
+ //------------------------------------------------------------------
+ /// CPU subtype get accessor.
+ ///
+ /// @return The current value of the CPU subtype.
+ //------------------------------------------------------------------
+ uint32_t
+ GetCPUSubtype () const;
+
+ //------------------------------------------------------------------
+ /// CPU type get accessor.
+ ///
+ /// @return The current value of the CPU type.
+ //------------------------------------------------------------------
+ uint32_t
+ GetCPUType () const;
+
+ //------------------------------------------------------------------
+ /// Feature flags get accessor.
+ ///
+ /// @return The current value of the CPU feature flags.
+ //------------------------------------------------------------------
+ uint32_t
+ GetFeatureFlags () const;
+
+ //------------------------------------------------------------------
+ /// Get register names of the current architecture.
+ ///
+ /// Get register names of the current architecture given
+ /// a register number, and a flavor for that register number.
+ /// There are many different register numbering schemes used
+ /// on a host:
+ /// @li \c eRegisterKindGCC - gcc compiler register numbering
+ /// @li \c eRegisterKindDWARF - DWARF register numbering
+ ///
+ /// @param[in] reg_num The register number to decode.
+ /// @param[in] flavor The flavor of the \a reg_num.
+ ///
+ /// @return the name of the register as a NULL terminated C string,
+ /// or /c NULL if the \a reg_num is invalid for \a flavor.
+ /// String values that are returned do not need to be freed.
+ //------------------------------------------------------------------
+ const char *
+ GetRegisterName (uint32_t reg_num, uint32_t flavor) const;
+
+ //------------------------------------------------------------------
+ /// Get register names for a specified architecture.
+ ///
+ /// Get register names of the specified architecture given
+ /// a register number, and a flavor for that register number.
+ /// There are many different register numbering schemes used
+ /// on a host:
+ ///
+ /// @li compiler register numbers (@see eRegisterKindGCC)
+ /// @li DWARF register numbers (@see eRegisterKindDWARF)
+ ///
+ /// @param[in] cpu The cpu type of the architecture specific
+ /// register
+ /// @param[in] subtype The cpu subtype of the architecture specific
+ /// register
+ /// @param[in] reg_num The register number to decode.
+ /// @param[in] flavor The flavor of the \a reg_num.
+ ///
+ /// @return the name of the register as a NULL terminated C string,
+ /// or /c NULL if the \a reg_num is invalid for \a flavor.
+ /// String values that are returned do not need to be freed.
+ //------------------------------------------------------------------
+ static const char *
+ GetRegisterName (uint32_t cpu, uint32_t subtype, uint32_t reg_num, uint32_t flavor);
+
+ //------------------------------------------------------------------
+ /// Test if the contained architecture is valid.
+ ///
+ /// @return true if the current architecture is valid, false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsValid () const;
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ //------------------------------------------------------------------
+ size_t
+ MemorySize() const;
+
+ //------------------------------------------------------------------
+ /// Change the CPU type and subtype given an architecture name.
+ ///
+ /// The architecture name supplied can also by 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).
+ ///
+ /// @param[in] arch_name The name of an architecture.
+ ///
+ /// @return true if \a arch_name was successfully transformed into
+ /// a valid cpu type and subtype.
+ //------------------------------------------------------------------
+ bool
+ SetArch (const char *arch_name);
+
+ bool
+ SetArchFromTargetTriple (const char *arch_name);
+ //------------------------------------------------------------------
+ /// Change the CPU type and subtype given new values of the cpu
+ /// type and subtype.
+ ///
+ /// @param[in] cpu The new CPU type
+ /// @param[in] subtype The new CPU subtype
+ //------------------------------------------------------------------
+ void
+ SetArch (uint32_t cpu, uint32_t subtype);
+
+ //------------------------------------------------------------------
+ /// Change the CPU subtype given a new value of the CPU subtype.
+ ///
+ /// @param[in] subtype The new CPU subtype.
+ //------------------------------------------------------------------
+ void
+ SetCPUSubtype (uint32_t subtype);
+
+ //------------------------------------------------------------------
+ /// Change the CPU type given a new value of the CPU type.
+ ///
+ /// @param[in] cpu The new CPU type.
+ //------------------------------------------------------------------
+ void
+ SetCPUType (uint32_t cpu);
+
+ //------------------------------------------------------------------
+ /// Returns the default endianness of the architecture.
+ ///
+ /// @return The endian enumeration for the default endianness of
+ /// the architecture.
+ //------------------------------------------------------------------
+ lldb::ByteOrder
+ GetDefaultEndian () const;
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ uint32_t m_cpu; ///< The cpu type of the architecture
+ uint32_t m_sub; ///< The cpu subtype of the architecture
+};
+
+
+//------------------------------------------------------------------
+/// @fn bool operator== (const ArchSpec& lhs, const ArchSpec& rhs)
+/// @brief Equal to operator.
+///
+/// Tests two ArchSpec objects to see if they are equal.
+///
+/// @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 equal to \a rhs
+//------------------------------------------------------------------
+bool operator==(const ArchSpec& lhs, const ArchSpec& rhs);
+
+//------------------------------------------------------------------
+/// @fn bool operator!= (const ArchSpec& lhs, const ArchSpec& rhs)
+/// @brief Not equal to operator.
+///
+/// Tests two ArchSpec objects to see if they are not equal.
+///
+/// @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 not equal to \a rhs
+//------------------------------------------------------------------
+bool operator!=(const ArchSpec& lhs, const ArchSpec& rhs);
+
+//------------------------------------------------------------------
+/// @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/lldb/include/lldb/Core/Args.h b/lldb/include/lldb/Core/Args.h
new file mode 100644
index 00000000000..79cb7599def
--- /dev/null
+++ b/lldb/include/lldb/Core/Args.h
@@ -0,0 +1,368 @@
+//===-- 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.h"
+#include "lldb/Core/Error.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+
+typedef std::pair<std::string, std::string> OptionArgPair;
+typedef std::vector<OptionArgPair> OptionArgVector;
+typedef lldb::SharedPtr<OptionArgVector>::Type OptionArgVectorSP;
+
+struct OptionArgElement
+{
+ 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/Core/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);
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// 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);
+ //------------------------------------------------------------------
+ /// 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 (int argc, 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);
+
+ // 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);
+
+ void
+ ParseArgsForCompletion (Options &options, OptionElementVector &option_element_vector);
+
+ //------------------------------------------------------------------
+ // Clear the arguments.
+ //
+ // For re-setting or blanking out the list of arguments.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ 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 lldb::addr_t
+ StringToAddress (const char *s, lldb::addr_t fail_value = LLDB_INVALID_ADDRESS, bool *success_ptr = NULL);
+
+ static bool
+ StringToBoolean (const char *s, bool fail_value, bool *success_ptr);
+
+ static int32_t
+ StringToOptionEnum (const char *s, lldb::OptionEnumValueElement *enum_values, int32_t fail_value, bool *success_ptr);
+
+ static lldb::ScriptLanguage
+ StringToScriptLanguage (const char *s, lldb::ScriptLanguage fail_value, bool *success_ptr);
+
+ static Error
+ StringToFormat (const char *s, lldb::Format &format);
+
+ // 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/lldb/include/lldb/Core/Baton.h b/lldb/include/lldb/Core/Baton.h
new file mode 100644
index 00000000000..7b9bd87d8d0
--- /dev/null
+++ b/lldb/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-include.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/lldb/include/lldb/Core/Broadcaster.h b/lldb/include/lldb/Core/Broadcaster.h
new file mode 100644
index 00000000000..c010417335d
--- /dev/null
+++ b/lldb/include/lldb/Core/Broadcaster.h
@@ -0,0 +1,194 @@
+//===-- 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 <string>
+#include <vector>
+
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+//#include "lldb/Core/Flags.h"
+#include "lldb/Core/Listener.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @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)
+/// };
+/// \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 (const char *name);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual since this class gets subclassed.
+ //------------------------------------------------------------------
+ virtual
+ ~Broadcaster();
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ 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 ();
+
+ 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);
+
+
+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;
+ // 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.
+ collection m_broadcaster_listeners; ///< A list of Listener / event_mask pairs that are listening to this broadcaster.
+ Mutex m_broadcaster_listeners_mutex; ///< A mutex that protects \a m_broadcaster_listeners.
+
+private:
+ //------------------------------------------------------------------
+ // For Broadcaster only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (Broadcaster);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Broadcaster_h_
diff --git a/lldb/include/lldb/Core/ClangForward.h b/lldb/include/lldb/Core/ClangForward.h
new file mode 100644
index 00000000000..3f4a2aee832
--- /dev/null
+++ b/lldb/include/lldb/Core/ClangForward.h
@@ -0,0 +1,103 @@
+//===-- 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 ASTContext;
+ class AddrLabelExpr;
+ class BinaryOperator;
+ class CodeGenerator;
+ class CompilerInstance;
+ class CXXBaseSpecifier;
+ class CXXBoolLiteralExpr;
+ class CXXFunctionalCastExpr;
+ class CXXNamedCastExpr;
+ class CXXRecordDecl;
+ class CXXThisExpr;
+ class CharacterLiteral;
+ class CompoundAssignOperator;
+ class Decl;
+ class DeclaratorDecl;
+ class DeclContext;
+ class DeclRefExpr;
+ class DeclStmt;
+ class Diagnostic;
+ class EnumDecl;
+ class Expr;
+ class ExtVectorElementExpr;
+ class FieldDecl;
+ class FloatingLiteral;
+ class FunctionDecl;
+ class GotoStmt;
+ class IdentifierTable;
+ class IntegerLiteral;
+ class LabelStmt;
+ class LangOptions;
+ class MemberExpr;
+ class NamedDecl;
+ class NamespaceDecl;
+ class NonTypeTemplateParmDecl;
+ class ObjCEncodeExpr;
+ class ObjCImplicitSetterGetterRefExpr;
+ class ObjCInterfaceDecl;
+ class ObjCIvarRefExpr;
+ class ObjCMessageExpr;
+ class ObjCMethodDecl;
+ class ObjCPropertyRefExpr;
+ class ObjCProtocolDecl;
+ class ObjCProtocolExpr;
+ class ObjCSelectorExpr;
+ class ObjCSuperExpr;
+ class ParenExpr;
+ class ParmVarDecl;
+ class PredefinedExpr;
+ 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 TemplateTemplateParmDecl;
+ class TemplateTypeParmDecl;
+ class TextDiagnosticBuffer;
+ class Type;
+ class TypedefDecl;
+ class TypesCompatibleExpr;
+ class UnaryOperator;
+ class ValueDecl;
+ class VarDecl;
+ struct PrintingPolicy;
+}
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_ClangForward_h_
diff --git a/lldb/include/lldb/Core/Communication.h b/lldb/include/lldb/Core/Communication.h
new file mode 100644
index 00000000000..dc8bfba4d92
--- /dev/null
+++ b/lldb/include/lldb/Core/Communication.h
@@ -0,0 +1,401 @@
+//===-- 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/Host.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Predicate.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 ();
+
+ //------------------------------------------------------------------
+ /// Poll for bytes available if the communications supports it.
+ ///
+ /// @param[in] timeout_usec
+ /// A timeout value in micro-seconds, UINT32_MAX for infinite
+ /// wait.
+ ///
+ /// @return
+ /// \b True if the bytes are, or became available within the
+ /// timeout period, \b false otherwise.
+ //------------------------------------------------------------------
+ virtual lldb::ConnectionStatus
+ BytesAvailable (uint32_t timeout_usec, Error *error_ptr);
+
+ //------------------------------------------------------------------
+ /// 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;
+ //------------------------------------------------------------------
+ /// Read bytes from the current connection.
+ ///
+ /// If no read thread is running, this function call the
+ /// connection's Connection::BytesAvailable(uint32_t) method to
+ /// wait for available data, and then call the
+ /// Connection::Read(void *, size_t) function to get any available
+ /// bytes if Connection::BytesAvailable(uint32_t) returned true.
+ ///
+ /// 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 bool Connection::BytesAvailable (uint32_t);
+ /// @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);
+
+private:
+ //------------------------------------------------------------------
+ // For Communication only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (Communication);
+
+protected:
+ std::auto_ptr<Connection> m_connection_ap; ///< 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.
+ ReadThreadBytesReceived m_callback;
+ void *m_callback_baton;
+
+ size_t
+ ReadFromConnection (void *dst,
+ size_t dst_len,
+ 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);
+
+ //------------------------------------------------------------------
+ /// 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/lldb/include/lldb/Core/Connection.h b/lldb/include/lldb/Core/Connection.h
new file mode 100644
index 00000000000..ca16930e8d0
--- /dev/null
+++ b/lldb/include/lldb/Core/Connection.h
@@ -0,0 +1,176 @@
+//===-- 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 ();
+
+ //------------------------------------------------------------------
+ /// Poll for bytes available if the communications supports it.
+ ///
+ /// @param[in] timeout_usec
+ /// A timeout value in micro-seconds.
+ ///
+ /// @param[out] error
+ /// A reference 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 bytes are, or became available within the
+ /// timeout period, \b false otherwise.
+ //------------------------------------------------------------------
+ virtual lldb::ConnectionStatus
+ BytesAvailable (uint32_t timeout_usec, Error *error_ptr) = 0;
+
+ //------------------------------------------------------------------
+ /// 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, 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/lldb/include/lldb/Core/ConnectionFileDescriptor.h b/lldb/include/lldb/Core/ConnectionFileDescriptor.h
new file mode 100644
index 00000000000..53a3997eab7
--- /dev/null
+++ b/lldb/include/lldb/Core/ConnectionFileDescriptor.h
@@ -0,0 +1,74 @@
+//===-- 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
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Connection.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
+ 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, lldb::ConnectionStatus &status, Error *error_ptr);
+
+ virtual size_t
+ Write (const void *src, size_t src_len, lldb::ConnectionStatus &status, Error *error_ptr);
+
+protected:
+ lldb::ConnectionStatus
+ SocketListen (uint16_t listen_port_num, Error *error_ptr);
+
+ lldb::ConnectionStatus
+ SocketConnect (const char *host_and_port, Error *error_ptr);
+
+ lldb::ConnectionStatus
+ Close (int& fd, Error *error);
+
+ int m_fd; // Socket we use to communicate once conn established
+ bool m_is_socket;
+ bool m_should_close_fd; // True if this class should close the file descriptor when it goes away.
+
+ static int
+ SetSocketOption(int fd, int level, int option_name, int option_value);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (ConnectionFileDescriptor);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ConnectionFileDescriptor_h_
diff --git a/lldb/include/lldb/Core/ConstString.h b/lldb/include/lldb/Core/ConstString.h
new file mode 100644
index 00000000000..9d95b96945b
--- /dev/null
+++ b/lldb/include/lldb/Core/ConstString.h
@@ -0,0 +1,396 @@
+//===-- 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"
+
+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 ref counted
+/// strings. Since the strings are uniqued, finding strings that are
+/// equal to one another is very fast (pointer compares). It also allows
+/// for many common strings from many different sources to be shared to
+/// keep the memory footprint low.
+//----------------------------------------------------------------------
+class ConstString
+{
+public:
+ //------------------------------------------------------------------
+ /// Default constructor
+ ///
+ /// Initializes the string to an empty string.
+ //------------------------------------------------------------------
+ ConstString ();
+
+ //------------------------------------------------------------------
+ /// Copy constructor
+ ///
+ /// Copies the string value in \a rhs and retains an extra reference
+ /// to the string value in the string pool.
+ ///
+ /// @param[in] rhs
+ /// Another string object to copy.
+ //------------------------------------------------------------------
+ ConstString (const ConstString& rhs);
+
+ //------------------------------------------------------------------
+ /// 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 does
+ /// exist, it retains an extra reference to the string in the string
+ /// pool. If it doesn't exist, it is added to the string pool with
+ /// a reference count of 1.
+ ///
+ /// @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.
+ ///
+ /// If the C string already exists in the global string pool, it
+ /// retains an extra reference to the string in the string
+ /// pool. If it doesn't exist, it is added to the string pool with
+ /// a reference count of 1.
+ ///
+ /// @param[in] cstr
+ /// A NULL terminated C string to add to the string pool.
+ ///
+ /// @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
+ ///
+ /// Decrements the reference count on the contained string, and if
+ /// the resulting reference count is zero, then the string is removed
+ /// from the global string pool. If the reference count is still
+ /// greater than zero, the string will remain in the string pool
+ /// until the last reference is released by other ConstString objects.
+ //------------------------------------------------------------------
+ ~ConstString ();
+
+ //----------------------------------------------------------------------
+ /// C string equality function object for CStrings contains in the
+ /// same StringPool only. (binary predicate).
+ //----------------------------------------------------------------------
+ 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 pointer 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
+ /// A pointer to this object if the string isn't empty, NULL
+ /// otherwise.
+ //------------------------------------------------------------------
+ operator void*() const;
+
+
+ //------------------------------------------------------------------
+ /// Assignment operator
+ ///
+ /// Assigns the string in this object with the value from \a rhs
+ /// and increments the reference count of that string.
+ ///
+ /// The previously contained string will be get its reference count
+ /// decremented and removed from the string pool if its reference
+ /// count reaches zero.
+ ///
+ /// @param[in] rhs
+ /// Another string object to copy into this object.
+ ///
+ /// @return
+ /// A const reference to this object.
+ //------------------------------------------------------------------
+ const ConstString&
+ operator = (const ConstString& rhs);
+
+ //------------------------------------------------------------------
+ /// 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 and reference
+ /// counted 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;
+
+ //------------------------------------------------------------------
+ /// 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 and reference
+ /// counted 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;
+
+ 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;
+
+
+ const char *
+ GetCString () const;
+
+ size_t
+ GetLength () const;
+ //------------------------------------------------------------------
+ /// Clear this object's state.
+ ///
+ /// Clear any contained string and reset the value to the an empty
+ /// string value.
+ ///
+ /// The previously contained string will be get its reference count
+ /// decremented and removed from the string pool if its reference
+ /// count reaches zero.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Compare two string objects.
+ ///
+ /// Compares the C string values contained in \a lhs and \a rhs and
+ /// returns an integer result.
+ ///
+ /// @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.
+ ///
+ /// Dump the string value and the reference count to the stream \a
+ /// s.
+ ///
+ /// @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;
+
+ //------------------------------------------------------------------
+ /// 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 retains an extra reference to the
+ /// string in the string pool. If it doesn't exist, it is added to
+ /// the string pool with a reference count of 1.
+ ///
+ /// @param[in] cstr
+ /// A NULL terminated C string to add to the string pool.
+ //------------------------------------------------------------------
+ void
+ SetCString (const char *cstr);
+
+ //------------------------------------------------------------------
+ /// 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 trim is false, then this allows strings
+ /// with NULL characters to be added to the string pool.
+ ///
+ /// If the C string already exists in the global string pool, it
+ /// retains an extra reference to the string in the string
+ /// pool. If it doesn't exist, it is added to the string pool with
+ /// a reference count of 1.
+ ///
+ /// @param[in] cstr
+ /// A NULL terminated C string to add to the string pool.
+ ///
+ /// @param[in] cstr_len
+ /// The absolute length of the C string if \a trim is false,
+ /// or the maximum length of the C string if \a trim is true.
+ ///
+ /// @param[in] trim
+ /// If \b true, trim \a cstr to it's actual length before adding
+ /// it to the string pool. If \b false then cstr_len is the
+ /// actual length of the C string to add.
+ //------------------------------------------------------------------
+ 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;
+
+ //------------------------------------------------------------------
+ /// 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 reference count 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/lldb/include/lldb/Core/DataBuffer.h b/lldb/include/lldb/Core/DataBuffer.h
new file mode 100644
index 00000000000..9acaea6cb5b
--- /dev/null
+++ b/lldb/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 size_t
+ GetByteSize() const = 0;
+};
+
+} // namespace lldb_private
+
+#endif /// #if defined(__cplusplus)
+#endif /// lldb_DataBuffer_h_
diff --git a/lldb/include/lldb/Core/DataBufferHeap.h b/lldb/include/lldb/Core/DataBufferHeap.h
new file mode 100644
index 00000000000..99fa2e57087
--- /dev/null
+++ b/lldb/include/lldb/Core/DataBufferHeap.h
@@ -0,0 +1,136 @@
+//===-- 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 (size_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, size_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 size_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.
+ //------------------------------------------------------------------
+ size_t
+ SetByteSize (size_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, size_t src_len);
+
+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/lldb/include/lldb/Core/DataBufferMemoryMap.h b/lldb/include/lldb/Core/DataBufferMemoryMap.h
new file mode 100644
index 00000000000..910601537eb
--- /dev/null
+++ b/lldb/include/lldb/Core/DataBufferMemoryMap.h
@@ -0,0 +1,156 @@
+//===-- 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 size_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_T_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_T_MAX, map
+ /// as many bytes as possible.
+ ///
+ /// @return
+ /// The number of bytes mapped starting from the \a offset.
+ //------------------------------------------------------------------
+ size_t
+ MemoryMapFromFileSpec (const FileSpec* file,
+ off_t offset = 0,
+ size_t length = SIZE_T_MAX);
+
+ //------------------------------------------------------------------
+ /// 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_T_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_T_MAX, map
+ /// as many bytes as possible.
+ ///
+ /// @return
+ /// The number of bytes mapped starting from the \a offset.
+ //------------------------------------------------------------------
+ size_t
+ MemoryMapFromFileDescriptor (int fd, off_t offset = 0, size_t length = SIZE_T_MAX);
+
+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.
+ size_t m_size; ///< The size of the data the user got when data was requested
+ Error m_error; ///< An error object that describes any errors that occurred during the memory mapping process
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (DataBufferMemoryMap);
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_DataBufferMemoryMap_h_
diff --git a/lldb/include/lldb/Core/DataExtractor.h b/lldb/include/lldb/Core/DataExtractor.h
new file mode 100644
index 00000000000..b6ac6e93d08
--- /dev/null
+++ b/lldb/include/lldb/Core/DataExtractor.h
@@ -0,0 +1,1124 @@
+//===-- 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;
+
+ //------------------------------------------------------------------
+ /// 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, 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.
+ //------------------------------------------------------------------
+ DataExtractor (lldb::DataBufferSP& data_sp, lldb::ByteOrder byte_order, uint8_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, uint32_t offset = 0, uint32_t length = UINT32_MAX);
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ uint32_t
+ PutToLog (Log *log,
+ uint32_t offset,
+ uint32_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.
+ //------------------------------------------------------------------
+ uint32_t
+ Dump(Stream *s,
+ uint32_t offset,
+ lldb::Format item_format,
+ uint32_t item_byte_size,
+ uint32_t item_count,
+ uint32_t num_per_line,
+ uint64_t base_addr,
+ uint32_t item_bit_size,
+ uint32_t item_bit_offset) 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, uint32_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 (uint32_t offset, uint32_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 (uint32_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.
+ //------------------------------------------------------------------
+ uint8_t
+ GetAddressByteSize () const;
+
+ //------------------------------------------------------------------
+ /// 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;
+
+ //------------------------------------------------------------------
+ /// 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 (uint32_t *offset_ptr) 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 (uint32_t *offset_ptr, uint32_t length) 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;
+
+ //------------------------------------------------------------------
+ /// 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;
+
+
+ //------------------------------------------------------------------
+ /// 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 integer value that was extracted, or zero on failure.
+ //------------------------------------------------------------------
+ float
+ GetFloat (uint32_t *offset_ptr) const;
+
+ double
+ GetDouble (uint32_t *offset_ptr) const;
+
+ long double
+ GetLongDouble (uint32_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 (uint32_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 (uint32_t *offset_ptr, uint32_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 (uint32_t *offset_ptr, uint32_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 (uint32_t *offset_ptr, uint32_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 (uint32_t *offset_ptr, uint32_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 (uint32_t *offset_ptr, uint32_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 (uint32_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;
+
+ //------------------------------------------------------------------
+ /// 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 ( uint32_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 ( uint32_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 (uint32_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 (uint32_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 (uint32_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 (uint32_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 (uint32_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 ( uint32_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 (uint32_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 (uint32_t *offset_ptr) const;
+
+ //------------------------------------------------------------------
+ /// 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 (uint32_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 (uint32_t offset, uint32_t length) const;
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// 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 \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.
+ //------------------------------------------------------------------
+ uint32_t
+ SetData (const DataExtractor& data, uint32_t offset = 0, uint32_t length = UINT_MAX);
+
+ //------------------------------------------------------------------
+ /// 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 (lldb::DataBufferSP& data_sp, uint32_t offset = 0, uint32_t length = UINT_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);
+
+ //------------------------------------------------------------------
+ /// 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 (uint32_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 (uint32_t offset) const;
+
+ //------------------------------------------------------------------
+ /// 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;
+
+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.
+ 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
+};
+
+} // namespace lldb_private
+
+#endif // #if defined (__cplusplus)
+#endif // #ifndef liblldb_DataExtractor_h_
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
new file mode 100644
index 00000000000..c5ae8842362
--- /dev/null
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -0,0 +1,170 @@
+//===-- 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/Interpreter/CommandInterpreter.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/SourceManager.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:
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static Debugger &
+ GetSharedInstance ();
+
+ ~Debugger ();
+
+ bool
+ GetAsyncExecution ();
+
+ void
+ SetAsyncExecution (bool async);
+
+ void
+ SetInputFileHandle (FILE *fh, bool tranfer_ownership);
+
+ void
+ SetOutputFileHandle (FILE *fh, bool tranfer_ownership);
+
+ void
+ SetErrorFileHandle (FILE *fh, bool tranfer_ownership);
+
+ FILE *
+ GetInputFileHandle ();
+
+ FILE *
+ GetOutputFileHandle ();
+
+ FILE *
+ GetErrorFileHandle ();
+
+ Stream&
+ GetOutputStream ()
+ {
+ return m_output_file;
+ }
+
+ Stream&
+ GetErrorStream ()
+ {
+ return m_error_file;
+ }
+
+ CommandInterpreter &
+ GetCommandInterpreter ();
+
+ Listener &
+ GetListener ();
+
+ SourceManager &
+ GetSourceManager ();
+
+ lldb::TargetSP
+ GetCurrentTarget ();
+
+ ExecutionContext
+ GetCurrentExecutionContext();
+ //------------------------------------------------------------------
+ /// 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 ();
+
+ 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);
+
+protected:
+
+ static void
+ DispatchInputCallback (void *baton, const void *bytes, size_t bytes_len);
+
+ void
+ ActivateInputReader (const lldb::InputReaderSP &reader_sp);
+
+ bool
+ CheckIfTopInputReaderIsDone ();
+
+ void
+ DisconnectInput();
+
+ bool m_async_execution;
+ Communication m_input_comm;
+ StreamFile m_input_file;
+ StreamFile m_output_file;
+ StreamFile m_error_file;
+ TargetList m_target_list;
+ Listener m_listener;
+ SourceManager m_source_manager;
+ CommandInterpreter m_command_interpreter;
+
+ std::stack<lldb::InputReaderSP> m_input_readers;
+ std::string m_input_reader_data;
+
+ typedef std::tr1::shared_ptr<Debugger> DebuggerSP;
+
+ static DebuggerSP &
+ GetDebuggerSP();
+
+ static int g_shared_debugger_refcount;
+ static bool g_in_terminate;
+
+private:
+ Debugger (); // Access the single global instance of this class using Debugger::GetSharedInstance();
+
+ DISALLOW_COPY_AND_ASSIGN (Debugger);
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_Debugger_h_
diff --git a/lldb/include/lldb/Core/Disassembler.h b/lldb/include/lldb/Core/Disassembler.h
new file mode 100644
index 00000000000..33d7d561dec
--- /dev/null
+++ b/lldb/include/lldb/Core/Disassembler.h
@@ -0,0 +1,138 @@
+//===-- 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>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/PluginInterface.h"
+
+namespace lldb_private {
+
+class ExecutionContext;
+
+class Disassembler :
+ public PluginInterface
+{
+public:
+ class Instruction
+ {
+ public:
+ typedef lldb::SharedPtr<Instruction>::Type shared_ptr;
+
+ Instruction();
+
+ virtual
+ ~Instruction();
+
+ virtual size_t
+ GetByteSize() const = 0;
+
+ virtual void
+ Dump (Stream *s, lldb::addr_t base_address, DataExtractor *bytes, uint32_t bytes_offset, const lldb_private::ExecutionContext exe_ctx, bool raw) = 0;
+
+ virtual bool
+ DoesBranch () const = 0;
+
+ virtual size_t
+ Extract (const DataExtractor& data, uint32_t data_offset) = 0;
+ };
+
+
+ class InstructionList
+ {
+ public:
+ InstructionList();
+ ~InstructionList();
+
+ size_t
+ GetSize() const;
+
+ Instruction *
+ GetInstructionAtIndex (uint32_t idx);
+
+ const Instruction *
+ GetInstructionAtIndex (uint32_t idx) const;
+
+ void
+ Clear();
+
+ void
+ AppendInstruction (Instruction::shared_ptr &inst_sp);
+
+ private:
+ typedef std::vector<Instruction::shared_ptr> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ collection m_instructions;
+ };
+
+
+ static Disassembler*
+ FindPlugin (const ArchSpec &arch);
+
+ static bool
+ Disassemble (const ArchSpec &arch,
+ const ExecutionContext &exe_ctx,
+ uint32_t mixed_context_lines,
+ Stream &strm);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ Disassembler(const ArchSpec &arch);
+ virtual ~Disassembler();
+
+ typedef const char * (*SummaryCallback)(const Instruction& inst, ExecutionContext *exe_context, void *user_data);
+
+ size_t
+ ParseInstructions (const ExecutionContext *exe_ctx,
+ lldb::AddressType addr_type,
+ lldb::addr_t addr,
+ size_t byte_size,
+ DataExtractor& data);
+
+ virtual size_t
+ ParseInstructions (const DataExtractor& data,
+ uint32_t data_offset,
+ uint32_t num_instructions,
+ lldb::addr_t base_addr) = 0;
+
+ InstructionList &
+ GetInstructionList ();
+
+ const InstructionList &
+ GetInstructionList () const;
+
+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;
+
+private:
+ //------------------------------------------------------------------
+ // For Disassembler only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (Disassembler);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Disassembler_h_
diff --git a/lldb/include/lldb/Core/Error.h b/lldb/include/lldb/Core/Error.h
new file mode 100644
index 00000000000..d4b8bab2383
--- /dev/null
+++ b/lldb/include/lldb/Core/Error.h
@@ -0,0 +1,291 @@
+//===-- 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)
+
+#include <mach/mach.h>
+#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.
+ //------------------------------------------------------------------
+ explicit
+ Error (ValueType err = 0, lldb::ErrorType type = lldb::eErrorTypeGeneric);
+
+ //------------------------------------------------------------------
+ /// 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 = (kern_return_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, ...);
+
+ //------------------------------------------------------------------
+ /// 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, ...);
+
+ //------------------------------------------------------------------
+ /// 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
+ SetError (kern_return_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, ...);
+
+ 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;
+
+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/lldb/include/lldb/Core/Event.h b/lldb/include/lldb/Core/Event.h
new file mode 100644
index 00000000000..66c5fbd7afa
--- /dev/null
+++ b/lldb/include/lldb/Core/Event.h
@@ -0,0 +1,180 @@
+//===-- 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
+ 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 ();
+
+ const EventData *
+ GetData () const;
+
+ uint32_t
+ GetType () const;
+
+ Broadcaster *
+ GetBroadcaster () const;
+
+ bool
+ BroadcasterIs (Broadcaster *broadcaster);
+
+ void
+ Clear();
+
+
+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);
+
+ Broadcaster * m_broadcaster; // The broadcaster that sent this event
+ uint32_t m_type; // The bit describing this event
+ std::auto_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/lldb/include/lldb/Core/FileSpec.h b/lldb/include/lldb/Core/FileSpec.h
new file mode 100644
index 00000000000..4aa17826c2b
--- /dev/null
+++ b/lldb/include/lldb/Core/FileSpec.h
@@ -0,0 +1,440 @@
+//===-- 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/Core/FileSpec.h"
+/// @brief A file utility class.
+///
+/// A file specification class that divides paths up into a directory
+/// and filename. These string values of the paths are put into uniqued
+/// string pools for fast comparisons and efficient memory usage.
+//----------------------------------------------------------------------
+class FileSpec
+{
+public:
+ typedef enum FileType
+ {
+ eFileTypeInvalid = -1,
+ eFileTypeUknown = 0,
+ eFileTypeDirectory,
+ eFileTypePipe,
+ eFileTypeRegular,
+ eFileTypeSocket,
+ eFileTypeSymbolicLink,
+ };
+
+ FileSpec();
+
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Takes an optional full path to a file. If \a path is valid,
+ /// this function will call FileSpec::SetFile (\a path).
+ ///
+ /// @param[in] path
+ /// The full or partial path to a file.
+ ///
+ /// @see FileSpec::SetFile ()
+ //------------------------------------------------------------------
+ explicit FileSpec (const char *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.
+ ///
+ /// The destructor is virtual in case this class is subclassed.
+ //------------------------------------------------------------------
+ virtual
+ ~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
+ void* () 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;
+
+ 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;
+
+ 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 or \a path.
+ ///
+ /// @return
+ /// \b true if the extracted fullpath fits into \a path, \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ bool
+ GetPath (char *path, size_t max_path_length) const;
+
+ FileType
+ GetFileType () 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;
+
+ //------------------------------------------------------------------
+ /// 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_T_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_T_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_T_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_T_MAX) const;
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ void
+ SetFile (const char *path);
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ bool
+ ReadFileLines (STLStringArray &lines);
+
+ static int
+ Resolve (const char *src_path, char *dst_path, size_t dst_len);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ ConstString m_directory; ///< The uniqued directory path
+ ConstString m_filename; ///< The uniqued filename path
+};
+
+//----------------------------------------------------------------------
+/// 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/lldb/include/lldb/Core/FileSpecList.h b/lldb/include/lldb/Core/FileSpecList.h
new file mode 100644
index 00000000000..c573bf847bc
--- /dev/null
+++ b/lldb/include/lldb/Core/FileSpecList.h
@@ -0,0 +1,196 @@
+//===-- 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/Core/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;
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @return
+ /// The index of the file that matches \a file if it is found,
+ /// else UINT32_MAX is returned.
+ //------------------------------------------------------------------
+ uint32_t
+ FindFileIndex (uint32_t idx, const FileSpec &file) 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 (uint32_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 (uint32_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;
+
+ //------------------------------------------------------------------
+ /// Get the number of files in the file list.
+ ///
+ /// @return
+ /// The number of files in the file spec list.
+ //------------------------------------------------------------------
+ uint32_t
+ GetSize () const;
+
+ 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/lldb/include/lldb/Core/Flags.h b/lldb/include/lldb/Core/Flags.h
new file mode 100644
index 00000000000..92452f3dfd0
--- /dev/null
+++ b/lldb/include/lldb/Core/Flags.h
@@ -0,0 +1,153 @@
+//===-- 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 flag bits.
+///
+/// The Flags class does bits.
+//----------------------------------------------------------------------
+class Flags
+{
+public:
+ //----------------------------------------------------------------------
+ /// The value type for flag bits is a 32 bit unsigned integer type.
+ //----------------------------------------------------------------------
+ typedef uint32_t ValueType;
+
+ //----------------------------------------------------------------------
+ /// Construct with initial flag bit values.
+ ///
+ /// Constructs this object with \a bits as the initial value for all
+ /// of the flag bits.
+ ///
+ /// @param[in] bits
+ /// The initial value for all flag bits.
+ //----------------------------------------------------------------------
+ Flags (ValueType bits = 0);
+
+ //----------------------------------------------------------------------
+ /// Copy constructor.
+ ///
+ /// Construct and copy the flag bits from \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A const Flags object reference to copy.
+ //----------------------------------------------------------------------
+ Flags (const Flags& rhs);
+
+ //----------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual in case this class is subclassed.
+ //----------------------------------------------------------------------
+ virtual
+ ~Flags ();
+
+ //----------------------------------------------------------------------
+ /// Get accessor for all flag bits.
+ ///
+ /// @return
+ /// Returns all of the flag bits as a Flags::ValueType.
+ //----------------------------------------------------------------------
+ ValueType
+ GetAllFlagBits () const;
+
+ size_t
+ GetBitSize() const;
+
+ //----------------------------------------------------------------------
+ /// Set accessor for all flag bits.
+ ///
+ /// @param[in] bits
+ /// The bits with which to replace all of the current flag bits.
+ //----------------------------------------------------------------------
+ void
+ SetAllFlagBits (ValueType bits);
+
+ //----------------------------------------------------------------------
+ /// Clear one or more flag bits.
+ ///
+ /// @param[in] bits
+ /// A bitfield containing one or more flag bits.
+ ///
+ /// @return
+ /// The new flag bits after clearing all bits from \a bits.
+ //----------------------------------------------------------------------
+ ValueType
+ Clear (ValueType bits);
+
+ //----------------------------------------------------------------------
+ /// Set one or more flag bits.
+ ///
+ /// @param[in] bits
+ /// A bitfield containing one or more flag bits.
+ ///
+ /// @return
+ /// The new flag bits after setting all bits from \a bits.
+ //----------------------------------------------------------------------
+ ValueType
+ Set (ValueType bits);
+
+ //----------------------------------------------------------------------
+ /// Test one or more flag bits.
+ ///
+ /// @return
+ /// \b true if \b any flag bits in \a bits are set, \b false
+ /// otherwise.
+ //----------------------------------------------------------------------
+ bool
+ IsSet (ValueType bits) const;
+
+ //----------------------------------------------------------------------
+ /// Test one or more flag bits.
+ ///
+ /// @return
+ /// \b true if \b all flag bits in \a bits are clear, \b false
+ /// otherwise.
+ //----------------------------------------------------------------------
+ bool
+ IsClear (ValueType bits) const;
+
+ //----------------------------------------------------------------------
+ /// 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;
+
+ //----------------------------------------------------------------------
+ /// 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;
+
+protected:
+ ValueType m_flags; ///< The flag bits.
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_Flags_h_
diff --git a/lldb/include/lldb/Core/IOStreamMacros.h b/lldb/include/lldb/Core/IOStreamMacros.h
new file mode 100644
index 00000000000..cc4eeb0e050
--- /dev/null
+++ b/lldb/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/lldb/include/lldb/Core/InputReader.h b/lldb/include/lldb/Core/InputReader.h
new file mode 100644
index 00000000000..2d876240c1d
--- /dev/null
+++ b/lldb/include/lldb/Core/InputReader.h
@@ -0,0 +1,114 @@
+//===-- 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 <termios.h>
+
+#include "lldb/lldb-include.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/Debugger.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);
+
+ InputReader ();
+
+ virtual
+ ~InputReader ();
+
+ virtual Error
+ Initialize (Callback callback,
+ void *baton,
+ lldb::InputReaderGranularity token_size,
+ const char *end_token,
+ const char *prompt,
+ bool echo);
+
+ 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;
+ }
+
+ // 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);
+
+ FILE *
+ GetInputFileHandle ();
+
+ FILE *
+ GetOutputFileHandle ();
+
+ bool
+ IsActive () const
+ {
+ return m_active;
+ }
+
+ const char *
+ GetPrompt () const;
+
+ void
+ RefreshPrompt();
+
+protected:
+ friend class Debugger;
+
+ void
+ Notify (lldb::InputReaderAction notification);
+
+ 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;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (InputReader);
+
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_InputReader_h_
diff --git a/lldb/include/lldb/Core/Language.h b/lldb/include/lldb/Core/Language.h
new file mode 100644
index 00000000000..f086cae3726
--- /dev/null
+++ b/lldb/include/lldb/Core/Language.h
@@ -0,0 +1,149 @@
+//===-- 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:
+
+ //------------------------------------------------------------------
+ /// Programming language type.
+ ///
+ /// These enumerations use the same language enumerations as the
+ /// DWARF specification for ease of use and consistency.
+ //------------------------------------------------------------------
+ typedef enum
+ {
+ Unknown = 0x0000, ///< Unknown or invalid language value.
+ C89 = 0x0001, ///< ISO C:1989.
+ C = 0x0002, ///< Non-standardized C, such as K&R.
+ Ada83 = 0x0003, ///< ISO Ada:1983.
+ C_plus_plus = 0x0004, ///< ISO C++:1998.
+ Cobol74 = 0x0005, ///< ISO Cobol:1974.
+ Cobol85 = 0x0006, ///< ISO Cobol:1985.
+ Fortran77 = 0x0007, ///< ISO Fortran 77.
+ Fortran90 = 0x0008, ///< ISO Fortran 90.
+ Pascal83 = 0x0009, ///< ISO Pascal:1983.
+ Modula2 = 0x000a, ///< ISO Modula-2:1996.
+ Java = 0x000b, ///< Java.
+ C99 = 0x000c, ///< ISO C:1999.
+ Ada95 = 0x000d, ///< ISO Ada:1995.
+ Fortran95 = 0x000e, ///< ISO Fortran 95.
+ PLI = 0x000f, ///< ANSI PL/I:1976.
+ ObjC = 0x0010, ///< Objective-C.
+ ObjC_plus_plus = 0x0011, ///< Objective-C++.
+ UPC = 0x0012, ///< Unified Parallel C.
+ D = 0x0013, ///< D.
+ Python = 0x0014, ///< Python.
+ } Type;
+
+ //------------------------------------------------------------------
+ /// Construct with optional language enumeration.
+ //------------------------------------------------------------------
+ Language(Language::Type language = Unknown);
+
+ //------------------------------------------------------------------
+ /// 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 Language::Type
+ /// 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.
+ //------------------------------------------------------------------
+ Language::Type
+ 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(Language::Type 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
+ //------------------------------------------------------------------
+ Language::Type 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/lldb/include/lldb/Core/Listener.h b/lldb/include/lldb/Core/Listener.h
new file mode 100644
index 00000000000..a47e1012239
--- /dev/null
+++ b/lldb/include/lldb/Core/Listener.h
@@ -0,0 +1,173 @@
+//===-- 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>
+
+
+// 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;
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ Listener (const char *name);
+
+ ~Listener ();
+
+ void
+ AddEvent (lldb::EventSP &event);
+
+ void
+ Clear ();
+
+ 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);
+
+protected:
+
+ //------------------------------------------------------------------
+ // 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;
+
+ 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;
+
+ void
+ BroadcasterWillDestruct (Broadcaster *);
+private:
+
+// 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/lldb/include/lldb/Core/Log.h b/lldb/include/lldb/Core/Log.h
new file mode 100644
index 00000000000..78017bb167e
--- /dev/null
+++ b/lldb/include/lldb/Core/Log.h
@@ -0,0 +1,243 @@
+//===-- 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 <sys/syslimits.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)
+
+//----------------------------------------------------------------------
+// Logging Functions
+//----------------------------------------------------------------------
+namespace lldb_private {
+
+class Log
+{
+public:
+
+ //------------------------------------------------------------------
+ // Callback definitions for abstracted plug-in log access.
+ //------------------------------------------------------------------
+ typedef void (*DisableCallback) ();
+ typedef Log* (*EnableCallback) (lldb::StreamSP &log_stream_sp,
+ uint32_t log_options,
+ Args &args,
+ Stream *feedback_strm);
+ typedef void (*ListCategoriesCallback) (Stream *strm);
+
+ typedef struct Callbacks
+ {
+ DisableCallback disable;
+ EnableCallback enable;
+ ListCategoriesCallback list_categories;
+ };
+
+ //------------------------------------------------------------------
+ // Static accessors for logging channels
+ //------------------------------------------------------------------
+ static void
+ RegisterLogChannel (const char *channel,
+ const Log::Callbacks &log_callbacks);
+
+ static bool
+ UnregisterLogChannel (const char *channel);
+
+ static bool
+ GetLogChannelCallbacks (const char *channel,
+ Log::Callbacks &log_callbacks);
+
+
+ static void
+ EnableAllLogChannels (lldb::StreamSP &log_stream_sp,
+ uint32_t log_options,
+ Args &args,
+ Stream *feedback_strm);
+
+ static void
+ DisableAllLogChannels ();
+
+ static void
+ ListAllLogChannels (Stream *strm);
+
+ //------------------------------------------------------------------
+ // Static accessors to STDOUT logging facilities.
+ //------------------------------------------------------------------
+ static void
+ STDOUT (const char *format, ...);
+
+ static lldb::StreamSP
+ GetStreamForSTDOUT ();
+
+ static void
+ SetStreamForSTDOUT (lldb::StreamSP &stream_sp);
+
+ //------------------------------------------------------------------
+ // Static accessors to STDERR logging facilities.
+ //------------------------------------------------------------------
+ static void
+ STDERR (const char *format, ...);
+
+ static lldb::StreamSP
+ GetStreamForSTDERR ();
+
+ static void
+ SetStreamForSTDERR (lldb::StreamSP &stream_sp);
+
+ //------------------------------------------------------------------
+ // Member functions
+ //------------------------------------------------------------------
+ Log ();
+
+ Log (lldb::StreamSP &stream_sp);
+
+ ~Log ();
+
+ void
+ PutCString (const char *cstr);
+
+ void
+ Printf (const char *format, ...);
+
+ void
+ VAPrintf (const char *format, va_list args);
+
+ void
+ PrintfWithFlags( uint32_t flags, const char *format, ...);
+
+ void
+ LogIf (uint32_t mask, const char *fmt, ...);
+
+ void
+ Debug (const char *fmt, ...);
+
+ void
+ DebugVerbose (const char *fmt, ...);
+
+ void
+ Error (const char *fmt, ...);
+
+ void
+ FatalError (int err, const char *fmt, ...);
+
+ void
+ Verbose (const char *fmt, ...);
+
+ void
+ Warning (const char *fmt, ...);
+
+ void
+ WarningVerbose (const char *fmt, ...);
+
+ Flags &
+ GetOptions();
+
+ const Flags &
+ GetOptions() const;
+
+ Flags &
+ GetMask();
+
+ const Flags &
+ GetMask() const;
+
+ bool
+ GetVerbose() const;
+
+ bool
+ GetDebug() const;
+
+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 const char *
+ GetPluginSuffix ();
+
+ static lldb::LogChannelSP
+ FindPlugin (const char *plugin_name);
+
+ virtual void
+ Disable () = 0;
+
+ virtual bool
+ Enable (lldb::StreamSP &log_stream_sp,
+ uint32_t log_options,
+ Stream *feedback_strm, // Feedback stream for argument errors etc
+ const Args &categories) = 0;// The categories to enable within this logging stream, if empty, enable default set
+
+ virtual void
+ ListCategories (Stream *strm) = 0;
+
+protected:
+ lldb::LogSP m_log_sp;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (LogChannel);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_Log_H_
diff --git a/lldb/include/lldb/Core/Mangled.h b/lldb/include/lldb/Core/Mangled.h
new file mode 100644
index 00000000000..bf99022651a
--- /dev/null
+++ b/lldb/include/lldb/Core/Mangled.h
@@ -0,0 +1,485 @@
+//===-- 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:
+
+ //------------------------------------------------------------------
+ /// Token type enumerations.
+ //------------------------------------------------------------------
+ enum TokenType
+ {
+ eInvalid, ///< Invalid token value (unitialized value)
+ eNameSpace, ///< The token is a namespace name.
+ eMethodName, ///< The token is a global or class method name
+ eType, ///< The token is a language type
+ eTemplate, ///< The token is a template class
+ eTemplateBeg, ///< The token that indicates the start of a template parameters
+ eTemplateEnd, ///< The token that indicates the end of a template parameters
+ eParamsBeg, ///< The start of a method's parameters (the open parenthesis)
+ eParamsEnd, ///< The end of a method's parameters (the open parenthesis)
+ eQualifier, ///< A language qualifier
+ eError, ///< The token failed to parse
+ };
+
+ //------------------------------------------------------------------
+ /// Mangled::Token structure
+ ///
+ /// As demangled names get tokenized, they get broken up into chunks
+ /// that have type enumerations (TokenType) and string values. Some of
+ /// the tokens are scopes (eTemplateBeg, eTemplateEnd, eParamsBeg,
+ /// eParamsEnd) that can indicate depth and searches can take
+ /// advantage of these to match using wildcards.
+ ///
+ /// For example the mangled string:
+ ///
+ /// "_ZNSbIhSt11char_traitsIhESaIhEE5eraseEmm"
+ ///
+ /// Demangles to:
+ ///
+ /// "std::basic_string<unsigned char, std::char_traits<unsigned char>, std::allocator<unsigned char> >::erase(unsigned long, unsigned long)"
+ ///
+ /// And tokenizes to:
+ /// @li eNameSpace ("std")
+ /// @li eTemplate ("basic_string")
+ /// @li eTemplateBeg ()
+ /// @li eType ("unsigned char")
+ /// @li eNameSpace ("std")
+ /// @li eTemplate ("char_traits")
+ /// @li eTemplateBeg ()
+ /// @li eType ("unsigned char")
+ /// @li eTemplateEnd ()
+ /// @li eNameSpace ("std")
+ /// @li eTemplate ("allocator")
+ /// @li eTemplateBeg ()
+ /// @li eType ("unsigned char"
+ /// @li eTemplateEnd ()
+ /// @li eTemplateEnd ()
+ /// @li eMethodName ("erase")
+ /// @li eParamsBeg ()
+ /// @li eType ("unsigned long")
+ /// @li eType ("unsigned long")
+ /// @li eParamsEnd ()
+ ///------------------------------------------------------------------
+ struct Token
+ {
+ //--------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Constructs this objet with an invalid token type and an
+ /// empty string.
+ //--------------------------------------------------------------
+ Token();
+
+ //--------------------------------------------------------------
+ /// Equal to operator.
+ ///
+ /// Tests if this object is equal to \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A const Mangled::Token object reference to compare
+ /// this object to.
+ ///
+ /// @return
+ /// \b true if this object is equal to \a rhs, \b false
+ /// otherwise.
+ //--------------------------------------------------------------
+ bool
+ operator== (const Token& rhs) const;
+
+ //--------------------------------------------------------------
+ /// Dump a description of this object to a Stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //--------------------------------------------------------------
+ void
+ Dump (Stream *s) const;
+
+ //--------------------------------------------------------------
+ /// Test if this token is a wildcard token.
+ ///
+ /// @return
+ /// Returns \b true if this token is a wildcard, \b false
+ /// otherwise.
+ //--------------------------------------------------------------
+ bool
+ IsWildcard() const;
+
+ //--------------------------------------------------------------
+ /// Members
+ //--------------------------------------------------------------
+ TokenType type; ///< The type of the token (Mangled::TokenType)
+ ConstString value; ///< The ConstString value associated with this token
+ };
+
+ //------------------------------------------------------------------
+ /// A collection of tokens.
+ ///
+ /// This class can be instantiated with a demangled names that can
+ /// be used as a query using the
+ /// Mangled::TokenList::MatchesQuery(const TokenList&) const
+ /// function.
+ //------------------------------------------------------------------
+ class TokenList
+ {
+ public:
+ //--------------------------------------------------------------
+ /// Construct with a demangled name.
+ ///
+ /// If demangled is valid the token list will parse up the
+ /// demangled string it is given, else the object will
+ /// initialize an empty token list.
+ //--------------------------------------------------------------
+ TokenList (const char *demangled = NULL);
+
+ //--------------------------------------------------------------
+ /// Destructor
+ //--------------------------------------------------------------
+ ~TokenList ();
+
+ //--------------------------------------------------------------
+ /// Clear the token list.
+ //--------------------------------------------------------------
+ void
+ Clear ();
+
+ //--------------------------------------------------------------
+ /// Dump a description of this object to a Stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //--------------------------------------------------------------
+ void
+ Dump (Stream *s) const;
+
+ //--------------------------------------------------------------
+ /// Find a token by Mangled::TokenType.
+ ///
+ /// Find the first token in the list that has \a token_type as
+ /// its type.
+ //--------------------------------------------------------------
+ const Token*
+ Find (TokenType token_type) const;
+
+ //--------------------------------------------------------------
+ /// Get a token by index.
+ ///
+ /// @return
+ /// The token at index \a idx, or NULL if the index is out
+ /// of range.
+ //--------------------------------------------------------------
+ const Token*
+ GetTokenAtIndex (uint32_t idx) const;
+
+ //--------------------------------------------------------------
+ /// Given a token list, see if it matches this object's tokens.
+ /// \a token_list can contain wild card values to enable powerful
+ /// matching. Matching the std::string::erase(*) example that was
+ /// tokenized above we could use a token list such as:
+ ///
+ /// token name
+ /// ----------- ----------------------------------------
+ /// eNameSpace "std"
+ /// eTemplate "basic_string"
+ /// eTemplateBeg
+ /// eInvalid "*"
+ /// eTemplateEnd
+ /// eMethodName "erase"
+ /// eParamsBeg
+ /// eInvalid "*"
+ /// eParamsEnd
+ ///
+ /// @return
+ /// Returns \b true if it \a token_list matches this
+ /// object's tokens, \b false otherwise.
+ //--------------------------------------------------------------
+ bool
+ MatchesQuery (const TokenList& token_list) const;
+
+ //--------------------------------------------------------------
+ /// Parses \a demangled into tokens.
+ ///
+ /// This allows complex comparisons to be done on demangled names. Comparisons can
+ /// include wildcards at the namespace, method name, template,
+ /// and template and parameter type levels.
+ ///
+ /// Example queries include:
+ /// "std::basic_string<*>" // Find all std::basic_string variants
+ /// "std::basic_string<*>::erase(*)" // Find all std::basic_string::erase variants with any number of parameters
+ /// "*::clear()" // Find all functions with a method name of
+ /// // "clear" that are in any namespace that
+ /// // have no parameters
+ /// "::printf" // Find the printf function in the global namespace
+ /// "printf" // Ditto
+ /// "foo::*(int)" // Find all functions in the class or namespace "foo" that take a single integer argument
+ ///
+ /// @return
+ /// The number of tokens that were decoded, or zero if
+ /// decoding fails.
+ //--------------------------------------------------------------
+ size_t
+ Parse (const char *demangled);
+
+ //--------------------------------------------------------------
+ /// Get the number of tokens in the list.
+ ///
+ /// @return
+ /// The number of tokens in the token list.
+ //--------------------------------------------------------------
+ size_t
+ Size () const;
+
+ protected:
+ //--------------------------------------------------------------
+ // Member variables.
+ //--------------------------------------------------------------
+ typedef std::vector<Token> collection; ///< The collection type for a list of Token objects.
+ collection m_tokens; ///< The token list.
+ private:
+ DISALLOW_COPY_AND_ASSIGN (TokenList);
+ };
+
+ //----------------------------------------------------------------------
+ /// 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 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 char *name, bool is_mangled);
+
+ //----------------------------------------------------------------------
+ /// 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;
+
+ //----------------------------------------------------------------------
+ /// Mangled name get accessor.
+ ///
+ /// @return
+ /// A reference to the mangled name string object.
+ //----------------------------------------------------------------------
+ ConstString&
+ GetMangledName ();
+
+ //----------------------------------------------------------------------
+ /// Mangled name get accessor.
+ ///
+ /// @return
+ /// A const reference to the mangled name string object.
+ //----------------------------------------------------------------------
+ const ConstString&
+ GetMangledName () const;
+
+ //----------------------------------------------------------------------
+ /// Best name get accessor.
+ ///
+ /// @return
+ /// A const reference to the the mangled name string object if this
+ /// object has a valid mangled name, else a const reference to the
+ /// demangled name is returned.
+ //----------------------------------------------------------------------
+ const ConstString&
+ GetName () const;
+
+ //----------------------------------------------------------------------
+ /// Generate the tokens from the demangled name.
+ ///
+ /// @param[out] tokens
+ /// A token list that will get filled in with the demangled tokens.
+ ///
+ /// @return
+ /// The number of tokens that were parsed and stored in \a tokens.
+ //----------------------------------------------------------------------
+ size_t
+ GetTokens (Mangled::TokenList &tokens) 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 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.
+ //----------------------------------------------------------------------
+ void
+ SetValue (const char *name, bool is_mangled);
+
+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);
+Stream& operator << (Stream& s, const Mangled::TokenList& obj);
+Stream& operator << (Stream& s, const Mangled::Token& obj);
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_Mangled_h_
diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
new file mode 100644
index 00000000000..d985ae9495f
--- /dev/null
+++ b/lldb/include/lldb/Core/Module.h
@@ -0,0 +1,597 @@
+//===-- 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/Section.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Symbol/TypeList.h"
+
+//----------------------------------------------------------------------
+/// @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.
+//----------------------------------------------------------------------
+namespace lldb_private {
+
+class Module :
+ public SymbolContextScope
+{
+public:
+ friend class ModuleList;
+
+ enum
+ {
+ flagsSearchedForObjParser = (1 << 0),
+ flagsSearchedForSymVendor = (1 << 1),
+ flagsParsedUUID = (1 << 2)
+ };
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~Module ();
+
+ //------------------------------------------------------------------
+ /// If you have an instance of Module, get its corresponding shared
+ /// pointer if it has one in the shared module list.
+ //------------------------------------------------------------------
+ lldb::ModuleSP
+ GetSP ();
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ CalculateSymbolContext (SymbolContext* sc);
+
+ //------------------------------------------------------------------
+ /// 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 files 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 functions by name.
+ ///
+ /// @param[in] name
+ /// The name of the function 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[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.
+ //------------------------------------------------------------------
+ uint32_t
+ FindFunctions (const ConstString &name, bool append, SymbolContextList& sc_list);
+
+ //------------------------------------------------------------------
+ /// Find functions by name.
+ ///
+ /// @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[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.
+ //------------------------------------------------------------------
+ uint32_t
+ FindFunctions (const RegularExpression& regex, 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] 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 UINT_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.
+ //------------------------------------------------------------------
+ uint32_t
+ FindGlobalVariables (const ConstString &name, bool append, uint32_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 UINT_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.
+ //------------------------------------------------------------------
+ uint32_t
+ FindGlobalVariables (const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variable_list);
+
+ //------------------------------------------------------------------
+ /// 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 UINT_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.
+ //------------------------------------------------------------------
+// uint32_t
+// FindTypes (const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, const char *udt_name, TypeList& type_list);
+
+ //------------------------------------------------------------------
+ /// Find types by name.
+ ///
+ /// @param[in] sc
+ /// A symbol context that scopes where to extract a type list
+ /// from.
+ ///
+ /// @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 UINT_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.
+ //------------------------------------------------------------------
+// uint32_t
+// FindTypes (const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, const char *udt_name, 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.
+ ///
+ /// @return
+ /// A const reference to the file specification object.
+ //------------------------------------------------------------------
+ const FileSpec &
+ GetFileSpec () const;
+
+
+ const TimeValue &
+ GetModificationTime () const;
+
+ //------------------------------------------------------------------
+ /// Get the number of compile units for this module.
+ ///
+ /// @return
+ /// The number of compile units that the symbol vendor plug-in
+ /// finds.
+ //------------------------------------------------------------------
+ uint32_t
+ GetNumCompileUnits();
+
+ lldb::CompUnitSP
+ GetCompileUnitAtIndex (uint32_t);
+
+ const ConstString &
+ GetObjectName() const;
+
+ off_t
+ GetObjectOffset() const;
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ ObjectFile *
+ GetObjectFile ();
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ SymbolVendor*
+ GetSymbolVendor(bool can_create = true);
+
+ //------------------------------------------------------------------
+ /// 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 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);
+
+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.
+ const ArchSpec m_arch; ///< The architecture for this module.
+ 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).
+ Flags m_flags; ///< Flags for this module to track what has been parsed already.
+ 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.
+ std::auto_ptr<ObjectFile> m_objfile_ap; ///< A pointer to the object file parser for this module.
+ std::auto_ptr<SymbolVendor> m_symfile_ap; ///< A pointer to the symbol vendor for this module.
+ //------------------------------------------------------------------
+ /// 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);
+
+private:
+
+ DISALLOW_COPY_AND_ASSIGN (Module);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Module_h_
diff --git a/lldb/include/lldb/Core/ModuleChild.h b/lldb/include/lldb/Core/ModuleChild.h
new file mode 100644
index 00000000000..0a8475a4425
--- /dev/null
+++ b/lldb/include/lldb/Core/ModuleChild.h
@@ -0,0 +1,103 @@
+//===-- 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 (Module* module);
+
+ //------------------------------------------------------------------
+ /// Copy constructor.
+ ///
+ /// @param[in] rhs
+ /// A const ModuleChild class reference to copy.
+ //------------------------------------------------------------------
+ ModuleChild (const ModuleChild& rhs);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual since this class is designed to be
+ /// inherited from.
+ //------------------------------------------------------------------
+ virtual
+ ~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 accessor for the module pointer.
+ ///
+ /// @return
+ /// A pointer to the module that owns this object.
+ //------------------------------------------------------------------
+ Module *
+ GetModule ();
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the module pointer.
+ ///
+ /// @return
+ /// A const pointer to the module that owns the object that
+ /// inherits from this class.
+ //------------------------------------------------------------------
+ Module *
+ 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 (Module *module);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ Module *m_module; ///< The Module that owns the object that inherits
+ ///< from this class.
+};
+
+} // namespace lldb_private
+
+
+#endif // liblldb_ModuleChild_h_
diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h
new file mode 100644
index 00000000000..e4959023857
--- /dev/null
+++ b/lldb/include/lldb/Core/ModuleList.h
@@ -0,0 +1,339 @@
+//===-- 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 "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:
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// 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 (lldb::ModuleSP &module_sp);
+
+ bool
+ AppendInNeeded (lldb::ModuleSP &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 ();
+
+ //------------------------------------------------------------------
+ /// 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;
+
+ uint32_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 (uint32_t idx);
+
+ //------------------------------------------------------------------
+ /// 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 (uint32_t idx) const;
+
+ //------------------------------------------------------------------
+ /// Find functions by name.
+ ///
+ /// Finds all functions that match \a name in all of the modules and
+ /// returns the results in \a sc_list.
+ ///
+ /// @param[in] name
+ /// The name of the function we are looking for.
+ ///
+ /// @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,
+ 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 UINT_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.
+ //------------------------------------------------------------------
+ uint32_t
+ FindGlobalVariables (const ConstString &name,
+ bool append,
+ uint32_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 UINT_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.
+ //------------------------------------------------------------------
+ uint32_t
+ FindGlobalVariables (const RegularExpression& regex,
+ bool append,
+ uint32_t max_matches,
+ VariableList& variable_list);
+
+ //------------------------------------------------------------------
+ /// 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 FileSpec *file_spec_ptr,
+ const ArchSpec *arch_ptr,
+ const UUID *uuid_ptr,
+ const ConstString *object_name,
+ ModuleList& matching_module_list) const;
+
+ lldb::ModuleSP
+ FindModule (lldb_private::Module *module_ptr);
+
+ lldb::ModuleSP
+ FindFirstModuleForFileSpec (const FileSpec &file_spec,
+ const ConstString *object_name = NULL);
+
+ size_t
+ FindSymbolsWithNameAndType (const ConstString &name,
+ lldb::SymbolType symbol_type,
+ SymbolContextList &sc_list);
+
+
+ bool
+ Remove (lldb::ModuleSP &module_sp);
+
+ bool
+ ResolveFileAddress (lldb::addr_t vm_addr,
+ Address& so_addr);
+
+ //------------------------------------------------------------------
+ /// @copydoc Module::ResolveSymbolContextForAddress (const Address &,uint32_t,SymbolContext&)
+ //------------------------------------------------------------------
+ uint32_t
+ ResolveSymbolContextForAddress (const Address& so_addr,
+ uint32_t resolve_scope,
+ SymbolContext& sc);
+
+ //------------------------------------------------------------------
+ /// @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);
+
+ //------------------------------------------------------------------
+ /// @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);
+
+ //------------------------------------------------------------------
+ /// Gets the size of the module list.
+ ///
+ /// @return
+ /// The number of modules in the module list.
+ //------------------------------------------------------------------
+ size_t
+ GetSize () const;
+
+ static const lldb::ModuleSP
+ GetModuleSP (lldb_private::Module *module_ptr);
+
+ static Error
+ GetSharedModule (const FileSpec& file_spec,
+ const ArchSpec& arch,
+ const UUID *uuid_ptr,
+ const ConstString *object_name,
+ off_t object_offset,
+ lldb::ModuleSP &module_sp,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr);
+
+protected:
+ //------------------------------------------------------------------
+ // Class typedefs.
+ //------------------------------------------------------------------
+ typedef std::vector<lldb::ModuleSP> collection; ///< The module collection type.
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ collection m_modules; ///< The collection of modules.
+ mutable Mutex m_modules_mutex;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ModuleList_h_
diff --git a/lldb/include/lldb/Core/Options.h b/lldb/include/lldb/Core/Options.h
new file mode 100644
index 00000000000..acdd3118fae
--- /dev/null
+++ b/lldb/include/lldb/Core/Options.h
@@ -0,0 +1,296 @@
+//===-- 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/Core/Args.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Options Options.h "lldb/Core/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:
+/// \code
+/// #include <getopt.h>
+/// int getopt_long(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 (int 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 () : 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 ();
+
+ 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
+ //------------------------------------------------------------------
+ struct option *
+ GetLongOptions ();
+
+ void
+ OptionSeen (int option_idx);
+
+ 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
+// BuildAliasOptions (OptionArgVector *option_arg_vector, Args args);
+
+ void
+ OutputFormattedUsageText (Stream &strm,
+ const char *text,
+ uint32_t output_max_columns);
+
+ void
+ GenerateOptionUsage (Stream &strm,
+ CommandObject *cmd,
+ const char *program_name = NULL);
+
+ // The following two pure virtual functions must be defined by every class that inherits from
+ // this class.
+
+ virtual const lldb::OptionDefinition*
+ GetDefinitions () = 0;
+
+ virtual void
+ ResetOptionValues () = 0;
+
+ //------------------------------------------------------------------
+ /// 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
+ //------------------------------------------------------------------
+ virtual Error
+ SetOptionValue (int 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] 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,
+ lldb_private::CommandInterpreter *interpreter,
+ lldb_private::StringList &matches);
+
+ //------------------------------------------------------------------
+ /// 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] 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[in] interpreter
+ /// The interpreter that's doing the completing.
+ ///
+ /// @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,
+ CommandInterpreter *interpreter,
+ StringList &matches);
+
+protected:
+ typedef std::set<char> OptionSet;
+
+ std::vector<struct option> m_getopt_table;
+ OptionSet m_seen_options;
+ std::vector<OptionSet> m_required_options;
+ std::vector<OptionSet> 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);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Options_h_
diff --git a/lldb/include/lldb/Core/PluginInterface.h b/lldb/include/lldb/Core/PluginInterface.h
new file mode 100644
index 00000000000..2c2823501fc
--- /dev/null
+++ b/lldb/include/lldb/Core/PluginInterface.h
@@ -0,0 +1,46 @@
+//===-- 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 const char *
+ GetPluginName() = 0;
+
+ virtual const char *
+ GetShortPluginName() = 0;
+
+ virtual uint32_t
+ GetPluginVersion() = 0;
+
+ virtual void
+ GetPluginCommandHelp (const char *command, Stream *strm) = 0;
+
+ virtual Error
+ ExecutePluginCommand (Args &command, Stream *strm) = 0;
+
+ virtual Log *
+ EnablePluginLogging (Stream *strm, Args &command) = 0;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_PluginInterface_h_
diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h
new file mode 100644
index 00000000000..fbd12a56dbb
--- /dev/null
+++ b/lldb/include/lldb/Core/PluginManager.h
@@ -0,0 +1,186 @@
+//===-- 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"
+
+namespace lldb_private {
+
+class PluginManager
+{
+public:
+ //------------------------------------------------------------------
+ // ABI
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const char *name,
+ const char *description,
+ ABICreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (ABICreateInstance create_callback);
+
+ static ABICreateInstance
+ GetABICreateCallbackAtIndex (uint32_t idx);
+
+ static ABICreateInstance
+ GetABICreateCallbackForPluginName (const char *name);
+
+
+ //------------------------------------------------------------------
+ // Disassembler
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const char *name,
+ const char *description,
+ DisassemblerCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (DisassemblerCreateInstance create_callback);
+
+ static DisassemblerCreateInstance
+ GetDisassemblerCreateCallbackAtIndex (uint32_t idx);
+
+ static DisassemblerCreateInstance
+ GetDisassemblerCreateCallbackForPluginName (const char *name);
+
+
+ //------------------------------------------------------------------
+ // DynamicLoader
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const char *name,
+ const char *description,
+ DynamicLoaderCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (DynamicLoaderCreateInstance create_callback);
+
+ static DynamicLoaderCreateInstance
+ GetDynamicLoaderCreateCallbackAtIndex (uint32_t idx);
+
+ static DynamicLoaderCreateInstance
+ GetDynamicLoaderCreateCallbackForPluginName (const char *name);
+
+
+ //------------------------------------------------------------------
+ // ObjectFile
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const char *name,
+ const char *description,
+ ObjectFileCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (ObjectFileCreateInstance create_callback);
+
+ static ObjectFileCreateInstance
+ GetObjectFileCreateCallbackAtIndex (uint32_t idx);
+
+ static ObjectFileCreateInstance
+ GetObjectFileCreateCallbackForPluginName (const char *name);
+
+
+ //------------------------------------------------------------------
+ // ObjectContainer
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const char *name,
+ const char *description,
+ ObjectContainerCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (ObjectContainerCreateInstance create_callback);
+
+ static ObjectContainerCreateInstance
+ GetObjectContainerCreateCallbackAtIndex (uint32_t idx);
+
+ static ObjectContainerCreateInstance
+ GetObjectContainerCreateCallbackForPluginName (const char *name);
+
+ //------------------------------------------------------------------
+ // LogChannel
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const char *name,
+ const char *description,
+ LogChannelCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (LogChannelCreateInstance create_callback);
+
+ static LogChannelCreateInstance
+ GetLogChannelCreateCallbackAtIndex (uint32_t idx);
+
+ static LogChannelCreateInstance
+ GetLogChannelCreateCallbackForPluginName (const char *name);
+
+ static const char *
+ GetLogChannelCreateNameAtIndex (uint32_t idx);
+
+ //------------------------------------------------------------------
+ // Process
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const char *name,
+ const char *description,
+ ProcessCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (ProcessCreateInstance create_callback);
+
+ static ProcessCreateInstance
+ GetProcessCreateCallbackAtIndex (uint32_t idx);
+
+ static ProcessCreateInstance
+ GetProcessCreateCallbackForPluginName (const char *name);
+
+ //------------------------------------------------------------------
+ // SymbolFile
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const char *name,
+ const char *description,
+ SymbolFileCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (SymbolFileCreateInstance create_callback);
+
+ static SymbolFileCreateInstance
+ GetSymbolFileCreateCallbackAtIndex (uint32_t idx);
+
+ static SymbolFileCreateInstance
+ GetSymbolFileCreateCallbackForPluginName (const char *name);
+
+
+ //------------------------------------------------------------------
+ // SymbolVendor
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const char *name,
+ const char *description,
+ SymbolVendorCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (SymbolVendorCreateInstance create_callback);
+
+ static SymbolVendorCreateInstance
+ GetSymbolVendorCreateCallbackAtIndex (uint32_t idx);
+
+ static SymbolVendorCreateInstance
+ GetSymbolVendorCreateCallbackForPluginName (const char *name);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_PluginManager_h_
diff --git a/lldb/include/lldb/Core/RegularExpression.h b/lldb/include/lldb/Core/RegularExpression.h
new file mode 100644
index 00000000000..23dabef1443
--- /dev/null
+++ b/lldb/include/lldb/Core/RegularExpression.h
@@ -0,0 +1,166 @@
+//===-- 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 <string>
+#include <vector>
+
+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:
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ RegularExpression (const char* re, int flags = REG_EXTENDED);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// Any previosuly compiled regular expression contained in this
+ /// object will be freed.
+ //------------------------------------------------------------------
+ ~RegularExpression ();
+
+ //------------------------------------------------------------------
+ /// 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, int flags = REG_EXTENDED);
+
+ //------------------------------------------------------------------
+ /// 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_count
+ /// The number of regmatch_t objects in \a match_ptr
+ ///
+ /// @param[out] match_ptr
+ /// A pointer to at least \a match_count regmatch_t objects
+ /// if \a match_count is non-zero.
+ ///
+ /// @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, size_t match_count = 0, int execute_flags = 0) const;
+
+ bool
+ GetMatchAtIndex (const char* s, uint32_t idx, std::string& match_str) 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;
+
+ //------------------------------------------------------------------
+ /// 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;
+
+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
+ mutable std::vector<regmatch_t> m_matches; ///< Where parenthesized subexpressions results are stored
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_DBRegex_h_
diff --git a/lldb/include/lldb/Core/STLUtils.h b/lldb/include/lldb/Core/STLUtils.h
new file mode 100644
index 00000000000..21b9a0af6c5
--- /dev/null
+++ b/lldb/include/lldb/Core/STLUtils.h
@@ -0,0 +1,104 @@
+//===-- 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 <ext/hash_fun.h>
+#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;
+ }
+};
+
+struct StdStringHash
+{
+ size_t operator()( const std::string& x ) const
+ {
+ return __gnu_cxx::hash<const char*>()( x.c_str() );
+ }
+};
+
+
+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/lldb/include/lldb/Core/Scalar.h b/lldb/include/lldb/Core/Scalar.h
new file mode 100644
index 00000000000..4207bb6f59e
--- /dev/null
+++ b/lldb/include/lldb/Core/Scalar.h
@@ -0,0 +1,302 @@
+//===-- 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();
+
+ size_t
+ GetByteSize() const;
+
+ bool
+ GetData (DataExtractor &data, size_t limit_byte_size = UINT32_MAX) 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);
+
+ 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, uint32_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 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 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);
+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/lldb/include/lldb/Core/SearchFilter.h b/lldb/include/lldb/Core/SearchFilter.h
new file mode 100644
index 00000000000..5864e85a141
--- /dev/null
+++ b/lldb/include/lldb/Core/SearchFilter.h
@@ -0,0 +1,326 @@
+//===-- 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/Stream.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Core/Module.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 (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 SymbolContext and a SymbolContextScope to see if
+ /// that SymbolContext passes the filter up to the level in \a scope.
+ ///
+ /// @param[in] context
+ /// The SymbolContext to check against the filter.
+ ///
+ /// @param[in] scope
+ /// The SymbolContextItem indicating what bits of the SymbolContextScope
+ /// to check against the filter.
+ ///
+ /// @return
+ /// \b true if \a SymbolContext passes, and \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ SymbolContextPasses (const SymbolContext &context,
+ lldb::SymbolContextItem scope);
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// 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 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 (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
+ SymbolContextPasses (const SymbolContext &context,
+ lldb::SymbolContextItem scope);
+
+ virtual bool
+ AddressPasses (Address &address);
+
+ virtual bool
+ CompUnitPasses (FileSpec &fileSpec);
+
+ virtual bool
+ CompUnitPasses (CompileUnit &compUnit);
+
+ virtual void
+ GetDescription(Stream *s);
+
+ virtual void
+ Dump (Stream *s) const;
+
+ virtual void
+ Search (Searcher &searcher);
+
+private:
+ FileSpec m_module_spec;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_SearchFilter_h_
diff --git a/lldb/include/lldb/Core/Section.h b/lldb/include/lldb/Core/Section.h
new file mode 100644
index 00000000000..358a7489523
--- /dev/null
+++ b/lldb/include/lldb/Core/Section.h
@@ -0,0 +1,231 @@
+//===-- 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/UserID.h"
+#include "lldb/Core/VMRange.h"
+
+namespace lldb_private {
+
+class SectionList
+{
+public:
+ typedef std::vector<lldb::SectionSP> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ SectionList();
+
+ virtual
+ ~SectionList();
+
+ uint32_t
+ AddSection (lldb::SectionSP& sect_sp);
+
+ uint32_t
+ AddUniqueSection (lldb::SectionSP& sect_sp);
+
+ uint32_t
+ FindSectionIndex (const Section* sect);
+
+ bool
+ ContainsSection(lldb::user_id_t sect_id) const;
+
+ void
+ Dump (Stream *s, Process *process, bool show_header) const;
+
+ lldb::SectionSP
+ FindSectionByName (const ConstString &section_dstr) const;
+
+// lldb::SectionSP
+// FindSectionByNames (const char *sect, ...) const;
+
+ lldb::SectionSP
+ FindSectionByID (lldb::user_id_t sect_id) const;
+
+ lldb::SectionSP
+ GetSharedPointer (const Section *section, bool check_children) const;
+
+ lldb::SectionSP
+ FindSectionContainingFileAddress (lldb::addr_t addr, uint32_t depth = UINT_MAX) const;
+
+ lldb::SectionSP
+ FindSectionContainingLinkedFileAddress (lldb::addr_t vm_addr) const;
+
+ bool
+ GetSectionData (const DataExtractor& module_data, DataExtractor& section_data) const;
+
+ // Get the number of sections in this list only
+ size_t
+ GetSize () const;
+
+ // 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, lldb::SectionSP& sect_sp, uint32_t depth = UINT_MAX);
+
+ lldb::SectionSP
+ GetSectionAtIndex (uint32_t idx) const;
+
+ size_t
+ Slide (lldb::addr_t slide_amount, bool slide_children);
+
+protected:
+ collection m_sections;
+};
+
+
+class Section :
+ public ModuleChild,
+ public UserID,
+ public Flags
+{
+public:
+ Section (
+ Section *parent, // NULL for top level sections, non-NULL for child sections
+ Module* module,
+ lldb::user_id_t sect_id,
+ const ConstString &name,
+ lldb::SectionType sect_type,
+ lldb::addr_t file_vm_addr,
+ lldb::addr_t vm_size,
+ uint64_t file_offset,
+ uint64_t file_size,
+ uint32_t flags);
+
+ ~Section ();
+
+ static int
+ Compare (const Section& a, const Section& b);
+
+ // Get a valid shared pointer to this section object
+ lldb::SectionSP
+ GetSharedPointer() const;
+
+ bool
+ ContainsFileAddress (lldb::addr_t vm_addr) const;
+
+ SectionList&
+ GetChildren ();
+
+ const SectionList&
+ GetChildren () const;
+
+ void
+ Dump (Stream *s, Process *process) const;
+
+ void
+ DumpName (Stream *s) const;
+
+ lldb::addr_t
+ GetLoadBaseAddress (Process *process) const;
+
+ bool
+ ResolveContainedAddress (lldb::addr_t offset, Address &so_addr) const;
+
+ uint64_t
+ GetFileOffset () const;
+
+ uint64_t
+ GetFileSize () const;
+
+ lldb::addr_t
+ GetFileAddress () const;
+
+ lldb::addr_t
+ GetOffset () const;
+
+ lldb::addr_t
+ GetByteSize () const;
+
+ void
+ SetByteSize (lldb::addr_t byte_size);
+
+ size_t
+ GetSectionDataFromImage (const DataExtractor& image_data, DataExtractor& section_data) const;
+
+ bool
+ IsFake() const;
+
+ void
+ SetIsFake(bool fake);
+
+ bool
+ IsDescendant (const Section *section);
+
+ size_t
+ MemoryMapSectionDataFromObjectFile (const ObjectFile* file, DataExtractor& section_data) const;
+
+ size_t
+ ReadSectionDataFromObjectFile (const ObjectFile* file, DataExtractor& section_data) const;
+
+ ConstString&
+ GetName ();
+
+ const ConstString&
+ GetName () const;
+
+ bool
+ Slide (lldb::addr_t slide_amount, bool slide_children);
+
+ void
+ SetLinkedLocation (const Section *linked_section, uint64_t linked_offset);
+
+ bool
+ ContainsLinkedFileAddress (lldb::addr_t vm_addr) const;
+
+ const Section *
+ GetLinkedSection () const;
+
+ uint64_t
+ GetLinkedOffset () const;
+
+ lldb::addr_t
+ GetLinkedFileAddress () const;
+
+ lldb::SectionType
+ GetSectionType () const
+ {
+ return m_type;
+ }
+
+protected:
+
+ Section * m_parent; // Parent section or NULL if no parent.
+ ConstString m_name; // Name of this section
+ lldb::SectionType m_type; // The type 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
+ uint64_t m_file_offset; // Object file offset (if any)
+ uint64_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; // 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.
+ const Section * m_linked_section;
+ uint64_t m_linked_offset;
+private:
+ DISALLOW_COPY_AND_ASSIGN (Section);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_Section_h_
diff --git a/lldb/include/lldb/Core/SourceManager.h b/lldb/include/lldb/Core/SourceManager.h
new file mode 100644
index 00000000000..6c6fdfdd602
--- /dev/null
+++ b/lldb/include/lldb/Core/SourceManager.h
@@ -0,0 +1,120 @@
+//===-- 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/Core/FileSpec.h"
+
+namespace lldb_private {
+
+class SourceManager
+{
+public:
+#ifndef SWIG
+ class File
+ {
+ public:
+ File (const FileSpec &file_spec);
+ ~File();
+
+ size_t
+ DisplaySourceLines (uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ Stream *s);
+
+ uint32_t
+ GetLineOffset (uint32_t line);
+
+ bool
+ LineIsValid (uint32_t line);
+
+ bool
+ FileSpecMatches (const FileSpec &file_spec);
+
+ protected:
+
+ bool
+ CalculateLineOffsets (uint32_t line = UINT32_MAX);
+
+ FileSpec m_file_spec;
+ lldb::DataBufferSP m_data_sp;
+ typedef std::vector<uint32_t> LineOffsets;
+ LineOffsets m_offsets;
+ };
+#endif
+
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SourceManager();
+
+ ~SourceManager();
+
+ typedef lldb::SharedPtr<File>::Type FileSP;
+
+ FileSP
+ GetFile (const FileSpec &file_spec);
+
+ size_t
+ DisplaySourceLines (const FileSpec &file,
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ Stream *s);
+
+ size_t
+ DisplaySourceLinesWithLineNumbers (const FileSpec &file,
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ const char* current_line_cstr,
+ Stream *s);
+
+ // This variant uses the last file we visited.
+ size_t
+ DisplaySourceLinesWithLineNumbersUsingLastFile (uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ const char* current_line_cstr,
+ Stream *s);
+
+ size_t
+ DisplayMoreWithLineNumbers (Stream *s);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from SourceManager can see and modify these
+ //------------------------------------------------------------------
+ typedef std::map <FileSpec, FileSP> FileCache;
+ FileCache m_file_cache;
+ FileSP m_last_file_sp;
+ uint32_t m_last_file_line;
+ uint32_t m_last_file_context_before;
+ uint32_t m_last_file_context_after;
+private:
+ //------------------------------------------------------------------
+ // For SourceManager only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (SourceManager);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_SourceManager_h_
diff --git a/lldb/include/lldb/Core/State.h b/lldb/include/lldb/Core/State.h
new file mode 100644
index 00000000000..2b9372ecd7d
--- /dev/null
+++ b/lldb/include/lldb/Core/State.h
@@ -0,0 +1,43 @@
+//===-- 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);
+
+bool
+StateIsRunningState (lldb::StateType state);
+
+bool
+StateIsStoppedState (lldb::StateType state);
+
+} // namespace lldb_private
+
+#endif // liblldb_State_h_
diff --git a/lldb/include/lldb/Core/Stream.h b/lldb/include/lldb/Core/Stream.h
new file mode 100644
index 00000000000..250bd1f2afd
--- /dev/null
+++ b/lldb/include/lldb/Core/Stream.h
@@ -0,0 +1,599 @@
+//===-- 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"
+
+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 int
+ Write (const void *src, size_t src_len) = 0;
+
+ //------------------------------------------------------------------
+ // Member functions
+ //------------------------------------------------------------------
+ int
+ 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.
+ //------------------------------------------------------------------
+ int
+ PrintfAsRawHex8 (const char *format, ...);
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ int
+ PutHex8 (uint8_t uvalue);
+
+ int
+ PutNHex8 (size_t n, uint8_t uvalue);
+
+ int
+ PutHex16 (uint16_t uvalue,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+
+ int
+ PutHex32 (uint32_t uvalue,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+
+ int
+ PutHex64 (uint64_t uvalue,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+
+ int
+ PutMaxHex64 (uint64_t uvalue,
+ size_t byte_size,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+ int
+ PutFloat (float f,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+
+ int
+ PutDouble (double d,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+
+ int
+ PutLongDouble (long double ld,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+
+ int
+ PutPointer (void *ptr);
+
+ int
+ PutBytesAsRawHex8 (const void *src,
+ size_t src_len,
+ lldb::ByteOrder src_byte_order,
+ lldb::ByteOrder dst_byte_order);
+
+ int
+ PutRawBytes (const void *s, size_t src_len,
+ lldb::ByteOrder src_byte_order,
+ lldb::ByteOrder dst_byte_order);
+
+ int
+ 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, int 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, int addr_size, const char *prefix = NULL, const char *suffix = NULL);
+
+ //------------------------------------------------------------------
+ /// Output a C string to the stream with optional format.
+ ///
+ /// Print a C string \a cstr to the stream using the printf format
+ /// in \a format.
+ ///
+ /// @param[in] format
+ /// The printf style format to use when outputting the C string.
+ //------------------------------------------------------------------
+ int
+ PutCString (const char *cstr);
+
+ //------------------------------------------------------------------
+ /// Output and End of Line character to the stream.
+ //------------------------------------------------------------------
+ int
+ 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.
+ //------------------------------------------------------------------
+ uint8_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;
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ int
+ 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.
+ //------------------------------------------------------------------
+ int
+ Printf (const char *format, ...);
+
+ int
+ 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 (uint8_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.
+ //------------------------------------------------------------------
+ int
+ 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.
+ //------------------------------------------------------------------
+ int
+ PutULEB128 (uint64_t uval);
+
+ static void
+ UnitTest(Stream *s);
+
+private:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ Flags m_flags; ///< Dump flags.
+ uint8_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.
+
+ int _PutHex8 (uint8_t uvalue, bool add_prefix);
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_Stream_h_
+
diff --git a/lldb/include/lldb/Core/StreamFile.h b/lldb/include/lldb/Core/StreamFile.h
new file mode 100644
index 00000000000..c83f3c2f01c
--- /dev/null
+++ b/lldb/include/lldb/Core/StreamFile.h
@@ -0,0 +1,76 @@
+//===-- 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"
+
+namespace lldb_private {
+
+class StreamFile : public Stream
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StreamFile ();
+
+ StreamFile (uint32_t flags, uint32_t addr_size, lldb::ByteOrder byte_order, FILE *f);
+
+ StreamFile (FILE *f);
+
+ StreamFile (uint32_t flags, uint32_t addr_size, lldb::ByteOrder byte_order, const char *path, const char *permissions = "w");
+
+ StreamFile (const char *path, const char *permissions = "w");
+
+ virtual
+ ~StreamFile();
+
+ void
+ Close ();
+
+ bool
+ Open (const char *path, const char *permissions = "w");
+
+ virtual void
+ Flush ();
+
+ virtual int
+ Write (const void *s, size_t length);
+
+ FILE *
+ GetFileHandle ();
+
+ void
+ SetFileHandle (FILE *file, bool close_file);
+
+ const char *
+ GetFilePathname ();
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from StreamFile can see and modify these
+ //------------------------------------------------------------------
+ FILE* m_file; ///< File handle to dump to.
+ bool m_close_file;
+ std::string m_path_name;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StreamFile_h_
diff --git a/lldb/include/lldb/Core/StreamString.h b/lldb/include/lldb/Core/StreamString.h
new file mode 100644
index 00000000000..699c7493fe9
--- /dev/null
+++ b/lldb/include/lldb/Core/StreamString.h
@@ -0,0 +1,61 @@
+//===-- 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 int
+ Write (const void *s, size_t length);
+
+ void
+ Clear();
+
+ void
+ Dump(FILE *f);
+
+ const char *
+ GetData () const;
+
+ size_t
+ GetSize() const;
+
+ std::string &
+ GetString();
+
+ const std::string &
+ GetString() const;
+
+protected:
+ std::string m_packet;
+
+};
+
+} // namespace lldb_private
+#endif // #ifndef liblldb_StreamString_h_
diff --git a/lldb/include/lldb/Core/StringList.h b/lldb/include/lldb/Core/StringList.h
new file mode 100644
index 00000000000..0b29bef54bf
--- /dev/null
+++ b/lldb/include/lldb/Core/StringList.h
@@ -0,0 +1,74 @@
+//===-- 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 "lldb/Core/STLUtils.h"
+
+namespace lldb_private {
+
+class StringList
+{
+public:
+
+ StringList ();
+
+ StringList (const char *str);
+
+ StringList (const char **strv, int strc);
+
+ virtual
+ ~StringList ();
+
+ 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);
+
+ uint32_t
+ GetSize ();
+
+ const char *
+ GetStringAtIndex (size_t idx);
+
+ 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);
+
+private:
+
+ STLStringArray m_strings;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StringList_h_
diff --git a/lldb/include/lldb/Core/TTYState.h b/lldb/include/lldb/Core/TTYState.h
new file mode 100644
index 00000000000..ad0b62f1b64
--- /dev/null
+++ b/lldb/include/lldb/Core/TTYState.h
@@ -0,0 +1,202 @@
+//===-- TTYState.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_TTYState_h_
+#define liblldb_TTYState_h_
+#if defined(__cplusplus)
+
+#include <termios.h>
+#include <stdint.h>
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class TTYState TTYState.h "lldb/Core/TTYState.h"
+/// @brief A TTY state managment class.
+///
+/// This class can be used to remember the TTY state for a file
+/// descriptor and later restore that state as it originally was.
+//----------------------------------------------------------------------
+class TTYState
+{
+public:
+ //------------------------------------------------------------------
+ /// Default constructor
+ //------------------------------------------------------------------
+ TTYState();
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~TTYState();
+
+ //------------------------------------------------------------------
+ /// 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 TTYState::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;
+
+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
+ //------------------------------------------------------------------
+ int m_fd; ///< File descriptor of the TTY.
+ int m_tflags; ///< Cached tflags information.
+ int m_ttystate_err; ///< Error value from call to save tflags.
+ struct termios m_ttystate; ///< Cached ttystate information.
+ lldb::pid_t m_process_group;///< Cached process group information.
+
+};
+
+//----------------------------------------------------------------------
+/// @class TTYStateSwitcher TTYState.h "lldb/Core/TTYState.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 TTYStateSwitcher
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ //------------------------------------------------------------------
+ TTYStateSwitcher();
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~TTYStateSwitcher();
+
+ //------------------------------------------------------------------
+ /// 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.
+ TTYState m_ttystates[2]; ///< The array of TTY states that holds saved TTY info.
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef liblldb_TTYState_h_
diff --git a/lldb/include/lldb/Core/ThreadSafeSTLMap.h b/lldb/include/lldb/Core/ThreadSafeSTLMap.h
new file mode 100644
index 00000000000..a8921e5a802
--- /dev/null
+++ b/lldb/include/lldb/Core/ThreadSafeSTLMap.h
@@ -0,0 +1,170 @@
+//===-- 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()
+ {
+ }
+
+ 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/lldb/include/lldb/Core/ThreadSafeValue.h b/lldb/include/lldb/Core/ThreadSafeValue.h
new file mode 100644
index 00000000000..42a5a5c6725
--- /dev/null
+++ b/lldb/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/lldb/include/lldb/Core/Timer.h b/lldb/include/lldb/Core/Timer.h
new file mode 100644
index 00000000000..50c8fdfd386
--- /dev/null
+++ b/lldb/include/lldb/Core/Timer.h
@@ -0,0 +1,93 @@
+//===-- 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 <memory>
+#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 an 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, ...);
+
+ //--------------------------------------------------------------
+ /// Desstructor
+ //--------------------------------------------------------------
+ ~Timer();
+
+ void
+ Dump ();
+
+ static void
+ SetDisplayDepth (uint32_t depth);
+
+ 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);
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef liblldb_Timer_h_
diff --git a/lldb/include/lldb/Core/UUID.h b/lldb/include/lldb/Core/UUID.h
new file mode 100644
index 00000000000..6e3402b9e74
--- /dev/null
+++ b/lldb/include/lldb/Core/UUID.h
@@ -0,0 +1,80 @@
+//===-- 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:
+ typedef uint8_t ValueType[16];
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ UUID ();
+ UUID (const UUID& rhs);
+ UUID (const void *uuid_bytes, uint32_t num_uuid_bytes);
+ UUID (const uuid_t *uuid);
+
+ ~UUID ();
+
+ const UUID&
+ operator=(const UUID& rhs);
+
+ void
+ Clear ();
+
+ void
+ Dump (Stream *s) const;
+
+ const void *
+ GetBytes() const;
+
+ static size_t
+ GetByteSize();
+
+ bool
+ IsValid () const;
+
+ void
+ SetBytes (const void *uuid_bytes);
+
+ char *
+ GetAsCString (char *dst, size_t dst_len) const;
+
+ size_t
+ SetfromCString (const char *c_str);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from UUID can see and modify these
+ //------------------------------------------------------------------
+ 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/lldb/include/lldb/Core/UniqueCStringMap.h b/lldb/include/lldb/Core/UniqueCStringMap.h
new file mode 100644
index 00000000000..34b91f30a6d
--- /dev/null
+++ b/lldb/include/lldb/Core/UniqueCStringMap.h
@@ -0,0 +1,232 @@
+//===-- 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>
+
+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 entry by index.
+ //
+ // The caller is responsible for ensuring that the collection does
+ // not change during while using the returned pointer.
+ //------------------------------------------------------------------
+ const T *
+ GetValueAtIndex (uint32_t idx) const
+ {
+ if (idx < m_map.size())
+ return &m_map[idx].value;
+ return NULL;
+ }
+
+ const char *
+ GetCStringAtIndex (uint32_t idx) const
+ {
+ if (idx < m_map.size())
+ return m_map[idx].cstring;
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ // 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 char *unique_cstr, const Entry *entry_ptr) const
+ {
+ const Entry *first_entry = m_map.data();
+ 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 == unique_cstr)
+ return next_entry;
+ }
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ // Get the total number of entries in this map.
+ //------------------------------------------------------------------
+ size_t
+ GetSize ()
+ {
+ 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());
+ }
+
+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/lldb/include/lldb/Core/UserID.h b/lldb/include/lldb/Core/UserID.h
new file mode 100644
index 00000000000..a12884afe6d
--- /dev/null
+++ b/lldb/include/lldb/Core/UserID.h
@@ -0,0 +1,123 @@
+//===-- 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);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual in case this class is subclassed.
+ //------------------------------------------------------------------
+ virtual
+ ~UserID ();
+
+ //------------------------------------------------------------------
+ /// Clears the object state.
+ ///
+ /// Clears the object contents back to a default invalid state.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Get accessor for the user ID.
+ ///
+ /// @return
+ /// The user ID.
+ //------------------------------------------------------------------
+ lldb::user_id_t
+ GetID () const;
+
+ //------------------------------------------------------------------
+ /// Set accessor for the user ID.
+ ///
+ /// @param[in] uid
+ /// The new user ID.
+ //------------------------------------------------------------------
+ void
+ SetID (lldb::user_id_t 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);
+
+ //--------------------------------------------------------------
+ /// Unary predicate function object callback.
+ //--------------------------------------------------------------
+ bool
+ operator () (const UserID& rhs) const;
+
+ 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.
+};
+
+//--------------------------------------------------------------
+/// Stream the UserID object to a Stream.
+//--------------------------------------------------------------
+bool operator== (const UserID& lhs, const UserID& rhs);
+bool operator!= (const UserID& lhs, const UserID& rhs);
+Stream& operator << (Stream& strm, const UserID& uid);
+
+} // namespace lldb_private
+
+#endif // liblldb_UserID_h_
diff --git a/lldb/include/lldb/Core/VMRange.h b/lldb/include/lldb/Core/VMRange.h
new file mode 100644
index 00000000000..b97059f2577
--- /dev/null
+++ b/lldb/include/lldb/Core/VMRange.h
@@ -0,0 +1,165 @@
+//===-- 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()
+ {
+ }
+
+ // 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 GetByteSize() > 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) 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);
+
+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/lldb/include/lldb/Core/Value.h b/lldb/include/lldb/Core/Value.h
new file mode 100644
index 00000000000..9aaf44abc72
--- /dev/null
+++ b/lldb/include/lldb/Core/Value.h
@@ -0,0 +1,172 @@
+//===-- 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 <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"
+
+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
+ 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
+ eContextTypeOpaqueClangQualType,// void * (an opaque clang::QualType * that can be fed to "static QualType QualType::getFromOpaquePtr(void *)")
+ eContextTypeDCRegisterInfo, // lldb::RegisterInfo *
+ eContextTypeDCType, // Type *
+ eContextTypeDCVariable, // Variable *
+ eContextTypeValue // Value * (making this a proxy value. Used when putting locals on the DWARF expression parser stack)
+ };
+
+ Value();
+ Value(const Scalar& scalar);
+ Value(int v);
+ Value(unsigned int v);
+ Value(long v);
+ Value(unsigned long v);
+ Value(long long v);
+ Value(unsigned long long v);
+ Value(float v);
+ Value(double v);
+ Value(long double v);
+ Value(const uint8_t *bytes, int len);
+ Value(const Value &v);
+
+ Value *
+ CreateProxy();
+
+ Value *
+ GetProxyTarget();
+
+ void *
+ GetOpaqueClangQualType();
+
+ ValueType
+ GetValueType() const;
+
+ lldb::AddressType
+ GetValueAddressType () const;
+
+ ContextType
+ GetContextType() const;
+
+ void
+ SetValueType (ValueType value_type);
+
+ void
+ ClearContext ();
+
+ void
+ SetContext (ContextType context_type, void *p);
+
+ lldb::RegisterInfo *
+ GetRegisterInfo();
+
+ Type *
+ GetType();
+
+ Scalar &
+ ResolveValue (ExecutionContext *exe_ctx, clang::ASTContext *ast_context);
+
+ Scalar &
+ GetScalar();
+
+ void
+ ResizeData(int len);
+
+ bool
+ ValueOf(ExecutionContext *exe_ctx, clang::ASTContext *ast_context);
+
+ Variable *
+ GetVariable();
+
+ void
+ Dump (Stream* strm);
+
+ lldb::Format
+ GetValueDefaultFormat ();
+
+ void *
+ GetValueOpaqueClangQualType ();
+
+ size_t
+ GetValueByteSize (clang::ASTContext *ast_context, Error *error_ptr);
+
+ Error
+ GetValueAsData (ExecutionContext *exe_ctx, clang::ASTContext *ast_context, DataExtractor &data, uint32_t data_offset);
+
+ static const char *
+ GetValueTypeAsCString (ValueType context_type);
+
+ static const char *
+ GetContextTypeAsCString (ContextType context_type);
+
+protected:
+ Scalar m_value;
+ ValueType m_value_type;
+ void * m_context;
+ ContextType m_context_type;
+ DataBufferHeap m_data_buffer;
+};
+
+class ValueList
+{
+public:
+ ValueList () {}
+ 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/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
new file mode 100644
index 00000000000..75ae31bdffb
--- /dev/null
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -0,0 +1,230 @@
+//===-- 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 <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/ExecutionContextScope.h"
+
+namespace lldb_private {
+
+class ValueObject : public UserID
+{
+public:
+ friend class ValueObjectList;
+
+ virtual ~ValueObject();
+
+ //------------------------------------------------------------------
+ // Sublasses must implement the functions below.
+ //------------------------------------------------------------------
+ virtual size_t
+ GetByteSize() = 0;
+
+ virtual clang::ASTContext *
+ GetClangAST () = 0;
+
+ virtual void *
+ GetOpaqueClangQualType () = 0;
+
+ virtual lldb::ValueType
+ GetValueType() const = 0;
+
+protected:
+ // Should only be called by ValueObject::GetNumChildren()
+ virtual uint32_t
+ CalculateNumChildren() = 0;
+
+public:
+ virtual ConstString
+ GetTypeName() = 0;
+
+ virtual void
+ UpdateValue (ExecutionContextScope *exe_scope) = 0;
+
+ //------------------------------------------------------------------
+ // Sublasses can implement the functions below if they need to.
+ //------------------------------------------------------------------
+protected:
+ // Should only be called by ValueObject::GetChildAtIndex()
+ virtual lldb::ValueObjectSP
+ CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index);
+
+public:
+
+ virtual bool
+ IsPointerType ();
+
+ virtual bool
+ IsPointerOrReferenceType ();
+
+ virtual bool
+ IsInScope (StackFrame *frame)
+ {
+ return true;
+ }
+
+ virtual off_t
+ GetByteOffset()
+ {
+ return 0;
+ }
+
+ virtual uint32_t
+ GetBitfieldBitSize()
+ {
+ return 0;
+ }
+
+ virtual uint32_t
+ GetBitfieldBitOffset()
+ {
+ return 0;
+ }
+
+ virtual const char *
+ GetValueAsCString (ExecutionContextScope *exe_scope);
+
+ virtual bool
+ SetValueFromCString (ExecutionContextScope *exe_scope, const char *value_str);
+
+ //------------------------------------------------------------------
+ // The functions below should NOT be modified by sublasses
+ //------------------------------------------------------------------
+ const Error &
+ GetError() const;
+
+ const ConstString &
+ GetName() const;
+
+ lldb::ValueObjectSP
+ GetChildAtIndex (uint32_t idx, bool can_create);
+
+ lldb::ValueObjectSP
+ GetChildMemberWithName (const ConstString &name, bool can_create);
+
+ uint32_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ uint32_t
+ GetNumChildren ();
+
+ const Value &
+ GetValue() const;
+
+ Value &
+ GetValue();
+
+ const char *
+ GetLocationAsCString (ExecutionContextScope *exe_scope);
+
+ const char *
+ GetSummaryAsCString (ExecutionContextScope *exe_scope);
+
+ lldb::user_id_t
+ GetUpdateID() const;
+
+ bool
+ GetValueIsValid ();
+
+ bool
+ GetValueDidChange () const;
+
+ bool
+ UpdateValueIfNeeded (ExecutionContextScope *exe_scope);
+
+ const DataExtractor &
+ GetDataExtractor () const;
+
+ DataExtractor &
+ GetDataExtractor ();
+
+ bool
+ Write ();
+
+ void
+ AddSyntheticChild (const ConstString &key,
+ lldb::ValueObjectSP& valobj_sp);
+
+ lldb::ValueObjectSP
+ GetSyntheticChild (const ConstString &key) const;
+
+ lldb::ValueObjectSP
+ GetSyntheticArrayMemberFromPointer (int32_t index, bool can_create);
+
+protected:
+ enum {
+ eValueChanged = (1 << 0),
+ eNumChildrenHasBeenSet = (1 << 1),
+ eValueIsValid = (1 << 2)
+ };
+ //------------------------------------------------------------------
+ // Classes that inherit from ValueObject can see and modify these
+ //------------------------------------------------------------------
+ lldb::user_id_t m_update_id; // An integer that specifies the update number for this value in
+ // this value object list. If this value object is asked to update itself
+ // it will first check if the update ID match the value object
+ // list update number. If the update numbers match, no update is
+ // needed, if it does not match, this value object should update its
+ // the next time it is asked.
+ 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.
+ Flags m_flags; // A boolean that indicates this value has changed
+ std::string m_value_str; // Cached value string that will get cleared if/when the value is updated.
+ 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::vector<lldb::ValueObjectSP> m_children;
+ std::map<ConstString, lldb::ValueObjectSP> m_synthetic_children;
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ValueObject ();
+
+ void
+ SetName (const char *name);
+
+ void
+ SetName (const ConstString &name);
+
+ void
+ SetNumChildren (uint32_t num_children);
+
+ void
+ SetValueDidChange (bool value_changed);
+
+ void
+ SetValueIsValid (bool valid);
+
+private:
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObject);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObject_h_
diff --git a/lldb/include/lldb/Core/ValueObjectChild.h b/lldb/include/lldb/Core/ValueObjectChild.h
new file mode 100644
index 00000000000..b5f842cfba9
--- /dev/null
+++ b/lldb/include/lldb/Core/ValueObjectChild.h
@@ -0,0 +1,95 @@
+//===-- 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
+#include "clang/AST/Type.h"
+// Project includes
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A child of another ValueObject.
+//----------------------------------------------------------------------
+class ValueObjectChild : public ValueObject
+{
+public:
+ ValueObjectChild (ValueObject *parent,
+ clang::ASTContext *clang_ast,
+ void *clang_type,
+ const ConstString &name,
+ uint32_t byte_size,
+ int32_t byte_offset,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset);
+
+
+ virtual ~ValueObjectChild();
+
+ virtual size_t
+ GetByteSize();
+
+ virtual off_t
+ GetByteOffset();
+
+ virtual uint32_t
+ GetBitfieldBitSize();
+
+ virtual uint32_t
+ GetBitfieldBitOffset();
+
+ virtual clang::ASTContext *
+ GetClangAST ();
+
+ virtual void *
+ GetOpaqueClangQualType ();
+
+ virtual lldb::ValueType
+ GetValueType() const;
+
+ virtual uint32_t
+ CalculateNumChildren();
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual void
+ UpdateValue (ExecutionContextScope *exe_scope);
+
+ virtual bool
+ IsInScope (StackFrame *frame);
+
+protected:
+ ValueObject* m_parent; // The parent value object of which this is a child of.
+ clang::ASTContext *m_clang_ast; // The clang AST that the clang type comes from
+ void *m_clang_type; // The type of the child in question within the parent (m_parent_sp)
+ ConstString m_type_name;
+ uint32_t m_byte_size;
+ int32_t m_byte_offset;
+ uint32_t m_bitfield_bit_size;
+ uint32_t m_bitfield_bit_offset;
+
+ uint32_t
+ GetByteOffset() const;
+//
+// void
+// ReadValueFromMemory (ValueObject* parent, lldb::addr_t address);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectChild);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectChild_h_
diff --git a/lldb/include/lldb/Core/ValueObjectList.h b/lldb/include/lldb/Core/ValueObjectList.h
new file mode 100644
index 00000000000..b312790acab
--- /dev/null
+++ b/lldb/include/lldb/Core/ValueObjectList.h
@@ -0,0 +1,74 @@
+//===-- 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);
+
+ lldb::ValueObjectSP
+ FindValueObjectByPointer (ValueObject *valobj);
+
+ uint32_t
+ GetSize() const;
+
+ lldb::ValueObjectSP
+ GetValueObjectAtIndex (uint32_t);
+
+ lldb::ValueObjectSP
+ FindValueObjectByValueName (const char *name);
+
+ lldb::ValueObjectSP
+ FindValueObjectByUID (lldb::user_id_t uid);
+
+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/lldb/include/lldb/Core/ValueObjectRegister.h b/lldb/include/lldb/Core/ValueObjectRegister.h
new file mode 100644
index 00000000000..fe3ac480caa
--- /dev/null
+++ b/lldb/include/lldb/Core/ValueObjectRegister.h
@@ -0,0 +1,168 @@
+//===-- 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/ValueObject.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A ValueObject that contains a root variable that may or may not
+// have children.
+//----------------------------------------------------------------------
+class ValueObjectRegisterContext : public ValueObject
+{
+public:
+ ValueObjectRegisterContext (RegisterContext *reg_ctx);
+
+ virtual
+ ~ValueObjectRegisterContext();
+
+ virtual size_t
+ GetByteSize();
+
+ virtual clang::ASTContext *
+ GetClangAST ();
+
+ virtual void *
+ GetOpaqueClangQualType ();
+
+ virtual lldb::ValueType
+ GetValueType () const
+ {
+ return lldb::eValueTypeRegisterSet;
+ }
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual uint32_t
+ CalculateNumChildren();
+
+ virtual void
+ UpdateValue (ExecutionContextScope *exe_scope);
+
+ virtual lldb::ValueObjectSP
+ CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index);
+
+protected:
+ RegisterContext *m_reg_ctx;
+
+private:
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectRegisterContext);
+};
+
+class ValueObjectRegisterSet : public ValueObject
+{
+public:
+ ValueObjectRegisterSet (RegisterContext *reg_ctx, uint32_t set_idx);
+
+ virtual
+ ~ValueObjectRegisterSet();
+
+ virtual size_t
+ GetByteSize();
+
+ virtual clang::ASTContext *
+ GetClangAST ();
+
+ virtual void *
+ GetOpaqueClangQualType ();
+
+ virtual lldb::ValueType
+ GetValueType () const
+ {
+ return lldb::eValueTypeRegisterSet;
+ }
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual uint32_t
+ CalculateNumChildren();
+
+ virtual void
+ UpdateValue (ExecutionContextScope *exe_scope);
+
+ virtual lldb::ValueObjectSP
+ CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index);
+
+protected:
+
+ RegisterContext *m_reg_ctx;
+ const lldb::RegisterSet *m_reg_set;
+ uint32_t m_reg_set_idx;
+
+private:
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectRegisterSet);
+};
+
+class ValueObjectRegister : public ValueObject
+{
+public:
+ ValueObjectRegister (RegisterContext *reg_ctx, uint32_t reg_num);
+
+ virtual
+ ~ValueObjectRegister();
+
+ virtual size_t
+ GetByteSize();
+
+ virtual clang::ASTContext *
+ GetClangAST ();
+
+ virtual void *
+ GetOpaqueClangQualType ();
+
+ virtual lldb::ValueType
+ GetValueType () const
+ {
+ return lldb::eValueTypeRegister;
+ }
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual uint32_t
+ CalculateNumChildren();
+
+ virtual void
+ UpdateValue (ExecutionContextScope *exe_scope);
+
+protected:
+
+ RegisterContext *m_reg_ctx;
+ const lldb::RegisterInfo *m_reg_info;
+ uint32_t m_reg_num;
+ ConstString m_type_name;
+ void *m_clang_type;
+
+private:
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectRegister);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectRegister_h_
diff --git a/lldb/include/lldb/Core/ValueObjectVariable.h b/lldb/include/lldb/Core/ValueObjectVariable.h
new file mode 100644
index 00000000000..80e0d05272e
--- /dev/null
+++ b/lldb/include/lldb/Core/ValueObjectVariable.h
@@ -0,0 +1,70 @@
+//===-- 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:
+ ValueObjectVariable (lldb::VariableSP &var_sp);
+
+ virtual
+ ~ValueObjectVariable();
+
+ virtual size_t
+ GetByteSize();
+
+ virtual clang::ASTContext *
+ GetClangAST ();
+
+ virtual void *
+ GetOpaqueClangQualType ();
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual uint32_t
+ CalculateNumChildren();
+
+ virtual lldb::ValueType
+ GetValueType() const;
+
+ virtual void
+ UpdateValue (ExecutionContextScope *exe_scope);
+
+ virtual bool
+ IsInScope (StackFrame *frame);
+
+protected:
+
+ lldb::VariableSP m_variable_sp; ///< The variable that this value object is based upon
+
+private:
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectVariable);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectVariable_h_
diff --git a/lldb/include/lldb/Core/dwarf.h b/lldb/include/lldb/Core/dwarf.h
new file mode 100644
index 00000000000..2b566dfd9d9
--- /dev/null
+++ b/lldb/include/lldb/Core/dwarf.h
@@ -0,0 +1,589 @@
+//===-- 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>
+
+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_ADDRESS (~(dw_addr_t)0)
+#define DW_INVALID_OFFSET (~(dw_offset_t)0)
+#define DW_INVALID_INDEX 0xFFFFFFFFul
+
+
+/* [7.5.4] Figure 16 "Tag Encodings" (pp. 125-127) in DWARFv3 draft 8 */
+
+#define DW_TAG_array_type 0x1
+#define DW_TAG_class_type 0x2
+#define DW_TAG_entry_point 0x3
+#define DW_TAG_enumeration_type 0x4
+#define DW_TAG_formal_parameter 0x5
+#define DW_TAG_imported_declaration 0x8
+#define DW_TAG_label 0xA
+#define DW_TAG_lexical_block 0xB
+#define DW_TAG_member 0xD
+#define DW_TAG_pointer_type 0xF
+#define DW_TAG_reference_type 0x10
+#define DW_TAG_compile_unit 0x11
+#define DW_TAG_string_type 0x12
+#define DW_TAG_structure_type 0x13
+#define DW_TAG_subroutine_type 0x15
+#define DW_TAG_typedef 0x16
+#define DW_TAG_union_type 0x17
+#define DW_TAG_unspecified_parameters 0x18
+#define DW_TAG_variant 0x19
+#define DW_TAG_common_block 0x1A
+#define DW_TAG_common_inclusion 0x1B
+#define DW_TAG_inheritance 0x1C
+#define DW_TAG_inlined_subroutine 0x1D
+#define DW_TAG_module 0x1E
+#define DW_TAG_ptr_to_member_type 0x1F
+#define DW_TAG_set_type 0x20
+#define DW_TAG_subrange_type 0x21
+#define DW_TAG_with_stmt 0x22
+#define DW_TAG_access_declaration 0x23
+#define DW_TAG_base_type 0x24
+#define DW_TAG_catch_block 0x25
+#define DW_TAG_const_type 0x26
+#define DW_TAG_constant 0x27
+#define DW_TAG_enumerator 0x28
+#define DW_TAG_file_type 0x29
+#define DW_TAG_friend 0x2A
+#define DW_TAG_namelist 0x2B
+#define DW_TAG_namelist_item 0x2C
+#define DW_TAG_packed_type 0x2D
+#define DW_TAG_subprogram 0x2E
+#define DW_TAG_template_type_parameter 0x2F
+#define DW_TAG_template_value_parameter 0x30
+#define DW_TAG_thrown_type 0x31
+#define DW_TAG_try_block 0x32
+#define DW_TAG_variant_part 0x33
+#define DW_TAG_variable 0x34
+#define DW_TAG_volatile_type 0x35
+#define DW_TAG_dwarf_procedure 0x36
+#define DW_TAG_restrict_type 0x37
+#define DW_TAG_interface_type 0x38
+#define DW_TAG_namespace 0x39
+#define DW_TAG_imported_module 0x3A
+#define DW_TAG_unspecified_type 0x3B
+#define DW_TAG_partial_unit 0x3C
+#define DW_TAG_imported_unit 0x3D
+#define DW_TAG_condition 0x3F
+#define DW_TAG_shared_type 0x40
+#define DW_TAG_lo_user 0x4080
+#define DW_TAG_hi_user 0xFFFF
+
+/* [7.5.4] Figure 17 "Child determination encodings" (p. 128) in DWARFv3 draft 8 */
+
+#define DW_CHILDREN_no 0x0
+#define DW_CHILDREN_yes 0x1
+
+/* [7.5.4] Figure 18 "Attribute encodings" (pp. 129-132) in DWARFv3 draft 8 */
+
+#define DW_AT_sibling 0x1
+#define DW_AT_location 0x2
+#define DW_AT_name 0x3
+#define DW_AT_ordering 0x9
+#define DW_AT_byte_size 0xB
+#define DW_AT_bit_offset 0xC
+#define DW_AT_bit_size 0xD
+#define DW_AT_stmt_list 0x10
+#define DW_AT_low_pc 0x11
+#define DW_AT_high_pc 0x12
+#define DW_AT_language 0x13
+#define DW_AT_discr 0x15
+#define DW_AT_discr_value 0x16
+#define DW_AT_visibility 0x17
+#define DW_AT_import 0x18
+#define DW_AT_string_length 0x19
+#define DW_AT_common_reference 0x1A
+#define DW_AT_comp_dir 0x1B
+#define DW_AT_const_value 0x1C
+#define DW_AT_containing_type 0x1D
+#define DW_AT_default_value 0x1E
+#define DW_AT_inline 0x20
+#define DW_AT_is_optional 0x21
+#define DW_AT_lower_bound 0x22
+#define DW_AT_producer 0x25
+#define DW_AT_prototyped 0x27
+#define DW_AT_return_addr 0x2A
+#define DW_AT_start_scope 0x2C
+#define DW_AT_bit_stride 0x2E
+#define DW_AT_upper_bound 0x2F
+#define DW_AT_abstract_origin 0x31
+#define DW_AT_accessibility 0x32
+#define DW_AT_address_class 0x33
+#define DW_AT_artificial 0x34
+#define DW_AT_base_types 0x35
+#define DW_AT_calling_convention 0x36
+#define DW_AT_count 0x37
+#define DW_AT_data_member_location 0x38
+#define DW_AT_decl_column 0x39
+#define DW_AT_decl_file 0x3A
+#define DW_AT_decl_line 0x3B
+#define DW_AT_declaration 0x3C
+#define DW_AT_discr_list 0x3D
+#define DW_AT_encoding 0x3E
+#define DW_AT_external 0x3F
+#define DW_AT_frame_base 0x40
+#define DW_AT_friend 0x41
+#define DW_AT_identifier_case 0x42
+#define DW_AT_macro_info 0x43
+#define DW_AT_namelist_item 0x44
+#define DW_AT_priority 0x45
+#define DW_AT_segment 0x46
+#define DW_AT_specification 0x47
+#define DW_AT_static_link 0x48
+#define DW_AT_type 0x49
+#define DW_AT_use_location 0x4A
+#define DW_AT_variable_parameter 0x4B
+#define DW_AT_virtuality 0x4C
+#define DW_AT_vtable_elem_location 0x4D
+#define DW_AT_allocated 0x4E
+#define DW_AT_associated 0x4F
+#define DW_AT_data_location 0x50
+#define DW_AT_byte_stride 0x51
+#define DW_AT_entry_pc 0x52
+#define DW_AT_use_UTF8 0x53
+#define DW_AT_extension 0x54
+#define DW_AT_ranges 0x55
+#define DW_AT_trampoline 0x56
+#define DW_AT_call_column 0x57
+#define DW_AT_call_file 0x58
+#define DW_AT_call_line 0x59
+#define DW_AT_description 0x5A
+#define DW_AT_binary_scale 0x5B
+#define DW_AT_decimal_scale 0x5C
+#define DW_AT_small 0x5D
+#define DW_AT_decimal_sign 0x5E
+#define DW_AT_digit_count 0x5F
+#define DW_AT_picture_string 0x60
+#define DW_AT_mutable 0x61
+#define DW_AT_threads_scaled 0x62
+#define DW_AT_explicit 0x63
+#define DW_AT_object_pointer 0x64
+#define DW_AT_endianity 0x65
+#define DW_AT_elemental 0x66
+#define DW_AT_pure 0x67
+#define DW_AT_recursive 0x68
+#define DW_AT_lo_user 0x2000
+#define DW_AT_hi_user 0x3FFF
+#define DW_AT_MIPS_fde 0x2001
+#define DW_AT_MIPS_loop_begin 0x2002
+#define DW_AT_MIPS_tail_loop_begin 0x2003
+#define DW_AT_MIPS_epilog_begin 0x2004
+#define DW_AT_MIPS_loop_unroll_factor 0x2005
+#define DW_AT_MIPS_software_pipeline_depth 0x2006
+#define DW_AT_MIPS_linkage_name 0x2007
+#define DW_AT_MIPS_stride 0x2008
+#define DW_AT_MIPS_abstract_name 0x2009
+#define DW_AT_MIPS_clone_origin 0x200A
+#define DW_AT_MIPS_has_inlines 0x200B
+/* GNU extensions. */
+#define DW_AT_sf_names 0x2101
+#define DW_AT_src_info 0x2102
+#define DW_AT_mac_info 0x2103
+#define DW_AT_src_coords 0x2104
+#define DW_AT_body_begin 0x2105
+#define DW_AT_body_end 0x2106
+#define DW_AT_GNU_vector 0x2107
+
+#define DW_AT_APPLE_repository_file 0x2501
+#define DW_AT_APPLE_repository_type 0x2502
+#define DW_AT_APPLE_repository_name 0x2503
+#define DW_AT_APPLE_repository_specification 0x2504
+#define DW_AT_APPLE_repository_import 0x2505
+#define DW_AT_APPLE_repository_abstract_origin 0x2506
+#define DW_AT_APPLE_optimized 0x3FE1
+#define DW_AT_APPLE_flags 0x3FE2
+#define DW_AT_APPLE_isa 0x3FE3
+#define DW_AT_APPLE_block 0x3FE4
+
+/* [7.5.4] Figure 19 "Attribute form encodings" (pp. 133-134) in DWARFv3 draft 8 */
+
+#define DW_FORM_addr 0x1
+#define DW_FORM_block2 0x3
+#define DW_FORM_block4 0x4
+#define DW_FORM_data2 0x5
+#define DW_FORM_data4 0x6
+#define DW_FORM_data8 0x7
+#define DW_FORM_string 0x8
+#define DW_FORM_block 0x9
+#define DW_FORM_block1 0xA
+#define DW_FORM_data1 0xB
+#define DW_FORM_flag 0xC
+#define DW_FORM_sdata 0xD
+#define DW_FORM_strp 0xE
+#define DW_FORM_udata 0xF
+#define DW_FORM_ref_addr 0x10
+#define DW_FORM_ref1 0x11
+#define DW_FORM_ref2 0x12
+#define DW_FORM_ref4 0x13
+#define DW_FORM_ref8 0x14
+#define DW_FORM_ref_udata 0x15
+#define DW_FORM_indirect 0x16 // cf section 7.5.3, "Abbreviations Tables", p. 119 DWARFv3 draft 8
+#define DW_FORM_APPLE_db_str 0x50 // read same as udata, but refers to string in repository
+
+/* [7.7.1] Figure 22 "DWARF operation encodings" (pp. 136-139) in DWARFv3 draft 8 */
+
+#define DW_OP_addr 0x3 // constant address (size target specific)
+#define DW_OP_deref 0x6
+#define DW_OP_const1u 0x8 // 1-byte constant
+#define DW_OP_const1s 0x9 // 1-byte constant
+#define DW_OP_const2u 0xA // 2-byte constant
+#define DW_OP_const2s 0xB // 2-byte constant
+#define DW_OP_const4u 0xC // 4-byte constant
+#define DW_OP_const4s 0xD // 4-byte constant
+#define DW_OP_const8u 0xE // 8-byte constant
+#define DW_OP_const8s 0xF // 8-byte constant
+#define DW_OP_constu 0x10 // ULEB128 constant
+#define DW_OP_consts 0x11 // SLEB128 constant
+#define DW_OP_dup 0x12
+#define DW_OP_drop 0x13
+#define DW_OP_over 0x14
+#define DW_OP_pick 0x15 // 1-byte stack index
+#define DW_OP_swap 0x16
+#define DW_OP_rot 0x17
+#define DW_OP_xderef 0x18
+#define DW_OP_abs 0x19
+#define DW_OP_and 0x1A
+#define DW_OP_div 0x1B
+#define DW_OP_minus 0x1C
+#define DW_OP_mod 0x1D
+#define DW_OP_mul 0x1E
+#define DW_OP_neg 0x1F
+#define DW_OP_not 0x20
+#define DW_OP_or 0x21
+#define DW_OP_plus 0x22
+#define DW_OP_plus_uconst 0x23 // ULEB128 addend
+#define DW_OP_shl 0x24
+#define DW_OP_shr 0x25
+#define DW_OP_shra 0x26
+#define DW_OP_xor 0x27
+#define DW_OP_skip 0x2F // signed 2-byte constant
+#define DW_OP_bra 0x28 // signed 2-byte constant
+#define DW_OP_eq 0x29
+#define DW_OP_ge 0x2A
+#define DW_OP_gt 0x2B
+#define DW_OP_le 0x2C
+#define DW_OP_lt 0x2D
+#define DW_OP_ne 0x2E
+#define DW_OP_lit0 0x30 // Literal 0
+#define DW_OP_lit1 0x31 // Literal 1
+#define DW_OP_lit2 0x32 // Literal 2
+#define DW_OP_lit3 0x33 // Literal 3
+#define DW_OP_lit4 0x34 // Literal 4
+#define DW_OP_lit5 0x35 // Literal 5
+#define DW_OP_lit6 0x36 // Literal 6
+#define DW_OP_lit7 0x37 // Literal 7
+#define DW_OP_lit8 0x38 // Literal 8
+#define DW_OP_lit9 0x39 // Literal 9
+#define DW_OP_lit10 0x3A // Literal 10
+#define DW_OP_lit11 0x3B // Literal 11
+#define DW_OP_lit12 0x3C // Literal 12
+#define DW_OP_lit13 0x3D // Literal 13
+#define DW_OP_lit14 0x3E // Literal 14
+#define DW_OP_lit15 0x3F // Literal 15
+#define DW_OP_lit16 0x40 // Literal 16
+#define DW_OP_lit17 0x41 // Literal 17
+#define DW_OP_lit18 0x42 // Literal 18
+#define DW_OP_lit19 0x43 // Literal 19
+#define DW_OP_lit20 0x44 // Literal 20
+#define DW_OP_lit21 0x45 // Literal 21
+#define DW_OP_lit22 0x46 // Literal 22
+#define DW_OP_lit23 0x47 // Literal 23
+#define DW_OP_lit24 0x48 // Literal 24
+#define DW_OP_lit25 0x49 // Literal 25
+#define DW_OP_lit26 0x4A // Literal 26
+#define DW_OP_lit27 0x4B // Literal 27
+#define DW_OP_lit28 0x4C // Literal 28
+#define DW_OP_lit29 0x4D // Literal 29
+#define DW_OP_lit30 0x4E // Literal 30
+#define DW_OP_lit31 0x4F // Literal 31
+#define DW_OP_reg0 0x50 // Contents of reg0
+#define DW_OP_reg1 0x51 // Contents of reg1
+#define DW_OP_reg2 0x52 // Contents of reg2
+#define DW_OP_reg3 0x53 // Contents of reg3
+#define DW_OP_reg4 0x54 // Contents of reg4
+#define DW_OP_reg5 0x55 // Contents of reg5
+#define DW_OP_reg6 0x56 // Contents of reg6
+#define DW_OP_reg7 0x57 // Contents of reg7
+#define DW_OP_reg8 0x58 // Contents of reg8
+#define DW_OP_reg9 0x59 // Contents of reg9
+#define DW_OP_reg10 0x5A // Contents of reg10
+#define DW_OP_reg11 0x5B // Contents of reg11
+#define DW_OP_reg12 0x5C // Contents of reg12
+#define DW_OP_reg13 0x5D // Contents of reg13
+#define DW_OP_reg14 0x5E // Contents of reg14
+#define DW_OP_reg15 0x5F // Contents of reg15
+#define DW_OP_reg16 0x60 // Contents of reg16
+#define DW_OP_reg17 0x61 // Contents of reg17
+#define DW_OP_reg18 0x62 // Contents of reg18
+#define DW_OP_reg19 0x63 // Contents of reg19
+#define DW_OP_reg20 0x64 // Contents of reg20
+#define DW_OP_reg21 0x65 // Contents of reg21
+#define DW_OP_reg22 0x66 // Contents of reg22
+#define DW_OP_reg23 0x67 // Contents of reg23
+#define DW_OP_reg24 0x68 // Contents of reg24
+#define DW_OP_reg25 0x69 // Contents of reg25
+#define DW_OP_reg26 0x6A // Contents of reg26
+#define DW_OP_reg27 0x6B // Contents of reg27
+#define DW_OP_reg28 0x6C // Contents of reg28
+#define DW_OP_reg29 0x6D // Contents of reg29
+#define DW_OP_reg30 0x6E // Contents of reg30
+#define DW_OP_reg31 0x6F // Contents of reg31
+#define DW_OP_breg0 0x70 // base register 0 + SLEB128 offset
+#define DW_OP_breg1 0x71 // base register 1 + SLEB128 offset
+#define DW_OP_breg2 0x72 // base register 2 + SLEB128 offset
+#define DW_OP_breg3 0x73 // base register 3 + SLEB128 offset
+#define DW_OP_breg4 0x74 // base register 4 + SLEB128 offset
+#define DW_OP_breg5 0x75 // base register 5 + SLEB128 offset
+#define DW_OP_breg6 0x76 // base register 6 + SLEB128 offset
+#define DW_OP_breg7 0x77 // base register 7 + SLEB128 offset
+#define DW_OP_breg8 0x78 // base register 8 + SLEB128 offset
+#define DW_OP_breg9 0x79 // base register 9 + SLEB128 offset
+#define DW_OP_breg10 0x7A // base register 10 + SLEB128 offset
+#define DW_OP_breg11 0x7B // base register 11 + SLEB128 offset
+#define DW_OP_breg12 0x7C // base register 12 + SLEB128 offset
+#define DW_OP_breg13 0x7D // base register 13 + SLEB128 offset
+#define DW_OP_breg14 0x7E // base register 14 + SLEB128 offset
+#define DW_OP_breg15 0x7F // base register 15 + SLEB128 offset
+#define DW_OP_breg16 0x80 // base register 16 + SLEB128 offset
+#define DW_OP_breg17 0x81 // base register 17 + SLEB128 offset
+#define DW_OP_breg18 0x82 // base register 18 + SLEB128 offset
+#define DW_OP_breg19 0x83 // base register 19 + SLEB128 offset
+#define DW_OP_breg20 0x84 // base register 20 + SLEB128 offset
+#define DW_OP_breg21 0x85 // base register 21 + SLEB128 offset
+#define DW_OP_breg22 0x86 // base register 22 + SLEB128 offset
+#define DW_OP_breg23 0x87 // base register 23 + SLEB128 offset
+#define DW_OP_breg24 0x88 // base register 24 + SLEB128 offset
+#define DW_OP_breg25 0x89 // base register 25 + SLEB128 offset
+#define DW_OP_breg26 0x8A // base register 26 + SLEB128 offset
+#define DW_OP_breg27 0x8B // base register 27 + SLEB128 offset
+#define DW_OP_breg28 0x8C // base register 28 + SLEB128 offset
+#define DW_OP_breg29 0x8D // base register 29 + SLEB128 offset
+#define DW_OP_breg30 0x8E // base register 30 + SLEB128 offset
+#define DW_OP_breg31 0x8F // base register 31 + SLEB128 offset
+#define DW_OP_regx 0x90 // ULEB128 register
+#define DW_OP_fbreg 0x91 // SLEB128 offset
+#define DW_OP_bregx 0x92 // ULEB128 register followed by SLEB128 offset
+#define DW_OP_piece 0x93 // ULEB128 size of piece addressed
+#define DW_OP_deref_size 0x94 // 1-byte size of data retrieved
+#define DW_OP_xderef_size 0x95 // 1-byte size of data retrieved
+#define DW_OP_nop 0x96
+#define DW_OP_push_object_address 0x97
+#define DW_OP_call2 0x98 // 2-byte offset of DIE
+#define DW_OP_call4 0x99 // 4-byte offset of DIE
+#define DW_OP_call_ref 0x9A // 4- or 8-byte offset of DIE
+#define DW_OP_lo_user 0xE0
+#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
+#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)
+#define DW_OP_hi_user 0xFF
+
+/* [7.8] Figure 23 "Base type encoding values" (pp. 140-141) in DWARFv3 draft 8 */
+
+#define DW_ATE_address 0x1
+#define DW_ATE_boolean 0x2
+#define DW_ATE_complex_float 0x3
+#define DW_ATE_float 0x4
+#define DW_ATE_signed 0x5
+#define DW_ATE_signed_char 0x6
+#define DW_ATE_unsigned 0x7
+#define DW_ATE_unsigned_char 0x8
+#define DW_ATE_imaginary_float 0x9
+#define DW_ATE_lo_user 0x80
+#define DW_ATE_hi_user 0xFF
+
+/* [7.9] Figure 24 "Accessibility encodings" (p. 141) in DWARFv3 draft 8 */
+
+#define DW_ACCESS_public 0x1
+#define DW_ACCESS_protected 0x2
+#define DW_ACCESS_private 0x3
+
+/* [7.10] Figure 25 "Visibility encodings" (p. 142) in DWARFv3 draft 8 */
+
+#define DW_VIS_local 0x1
+#define DW_VIS_exported 0x2
+#define DW_VIS_qualified 0x3
+
+/* [7.11] Figure 26 "Virtuality encodings" (p. 142) in DWARFv3 draft 8 */
+
+#define DW_VIRTUALITY_none 0x0
+#define DW_VIRTUALITY_virtual 0x1
+#define DW_VIRTUALITY_pure_virtual 0x2
+
+
+/* [7.12] Figure 27 "Language encodings" (p. 143) in DWARFv3 draft 8 */
+
+#define DW_LANG_C89 0x1
+#define DW_LANG_C 0x2
+#define DW_LANG_Ada83 0x3
+#define DW_LANG_C_plus_plus 0x4
+#define DW_LANG_Cobol74 0x5
+#define DW_LANG_Cobol85 0x6
+#define DW_LANG_Fortran77 0x7
+#define DW_LANG_Fortran90 0x8
+#define DW_LANG_Pascal83 0x9
+#define DW_LANG_Modula2 0xA
+#define DW_LANG_Java 0xB
+#define DW_LANG_C99 0xC
+#define DW_LANG_Ada95 0xD
+#define DW_LANG_Fortran95 0xE
+#define DW_LANG_PLI 0xF
+#define DW_LANG_lo_user 0x8000
+#define DW_LANG_hi_user 0xFFFF
+
+/* [7.13], "Address Class Encodings" (p. 144) in DWARFv3 draft 8 */
+
+#define DW_ADDR_none 0x0
+
+/* [7.14] Figure 28 "Identifier case encodings" (p. 144) in DWARFv3 draft 8 */
+
+#define DW_ID_case_sensitive 0x0
+#define DW_ID_up_case 0x1
+#define DW_ID_down_case 0x2
+#define DW_ID_case_insensitive 0x3
+
+/* [7.15] Figure 29 "Calling convention encodings" (p. 144) in DWARFv3 draft 8 */
+
+#define DW_CC_normal 0x1
+#define DW_CC_program 0x2
+#define DW_CC_nocall 0x3
+#define DW_CC_lo_user 0x40
+#define DW_CC_hi_user 0xFF
+
+/* [7.16] Figure 30 "Inline encodings" (p. 145) in DWARFv3 draft 8 */
+
+#define DW_INL_not_inlined 0x0
+#define DW_INL_inlined 0x1
+#define DW_INL_declared_not_inlined 0x2
+#define DW_INL_declared_inlined 0x3
+
+/* [7.17] Figure 31 "Ordering encodings" (p. 145) in DWARFv3 draft 8 */
+
+#define DW_ORD_row_major 0x0
+#define DW_ORD_col_major 0x1
+
+/* [7.18] Figure 32 "Discriminant descriptor encodings" (p. 146) in DWARFv3 draft 8 */
+
+#define DW_DSC_label 0x0
+#define DW_DSC_range 0x1
+
+/* [7.21] Figure 33 "Line Number Standard Opcode Encodings" (pp. 148-149) in DWARFv3 draft 8 */
+
+#define DW_LNS_copy 0x1
+#define DW_LNS_advance_pc 0x2
+#define DW_LNS_advance_line 0x3
+#define DW_LNS_set_file 0x4
+#define DW_LNS_set_column 0x5
+#define DW_LNS_negate_stmt 0x6
+#define DW_LNS_set_basic_block 0x7
+#define DW_LNS_const_add_pc 0x8
+#define DW_LNS_fixed_advance_pc 0x9
+#define DW_LNS_set_prologue_end 0xA
+#define DW_LNS_set_epilogue_begin 0xB
+#define DW_LNS_set_isa 0xC
+
+/* [7.21] Figure 34 "Line Number Extended Opcode Encodings" (p. 149) in DWARFv3 draft 8 */
+
+#define DW_LNE_end_sequence 0x1
+#define DW_LNE_set_address 0x2
+#define DW_LNE_define_file 0x3
+#define DW_LNE_lo_user 0x80
+#define DW_LNE_hi_user 0xFF
+
+/* [7.22] Figure 35 "Macinfo Type Encodings" (p. 150) in DWARFv3 draft 8 */
+
+#define DW_MACINFO_define 0x1
+#define DW_MACINFO_undef 0x2
+#define DW_MACINFO_start_file 0x3
+#define DW_MACINFO_end_file 0x4
+#define DW_MACINFO_vendor_ext 0xFF
+
+/* [7.23] Figure 36 "Call frame instruction encodings" (pp. 151-152) in DWARFv3 draft 8 */
+
+#define DW_CFA_advance_loc 0x40 // high 2 bits are 0x1, lower 6 bits are delta
+#define DW_CFA_offset 0x80 // high 2 bits are 0x2, lower 6 bits are register
+#define DW_CFA_restore 0xC0 // high 2 bits are 0x3, lower 6 bits are register
+#define DW_CFA_nop 0x0
+#define DW_CFA_set_loc 0x1
+#define DW_CFA_advance_loc1 0x2
+#define DW_CFA_advance_loc2 0x3
+#define DW_CFA_advance_loc4 0x4
+#define DW_CFA_offset_extended 0x5
+#define DW_CFA_restore_extended 0x6
+#define DW_CFA_undefined 0x7
+#define DW_CFA_same_value 0x8
+#define DW_CFA_register 0x9
+#define DW_CFA_remember_state 0xA
+#define DW_CFA_restore_state 0xB
+#define DW_CFA_def_cfa 0xC
+#define DW_CFA_def_cfa_register 0xD
+#define DW_CFA_def_cfa_offset 0xE
+#define DW_CFA_def_cfa_expression 0xF
+#define DW_CFA_expression 0x10
+#define DW_CFA_offset_extended_sf 0x11
+#define DW_CFA_def_cfa_sf 0x12
+#define DW_CFA_def_cfa_offset_sf 0x13
+#define DW_CFA_val_offset 0x14
+#define DW_CFA_val_offset_sf 0x15
+#define DW_CFA_val_expression 0x16
+#define DW_CFA_lo_user 0x1C
+#define DW_CFA_hi_user 0x3F
+
+/* FSF exception handling Pointer-Encoding constants (CFI augmentation) -- "DW_EH_PE_..." in the FSF sources */
+
+#define DW_GNU_EH_PE_absptr 0x0
+#define DW_GNU_EH_PE_uleb128 0x1
+#define DW_GNU_EH_PE_udata2 0x2
+#define DW_GNU_EH_PE_udata4 0x3
+#define DW_GNU_EH_PE_udata8 0x4
+#define DW_GNU_EH_PE_sleb128 0x9
+#define DW_GNU_EH_PE_sdata2 0xA
+#define DW_GNU_EH_PE_sdata4 0xB
+#define DW_GNU_EH_PE_sdata8 0xC
+#define DW_GNU_EH_PE_signed 0x8
+#define DW_GNU_EH_PE_MASK_ENCODING 0x0F
+#define DW_GNU_EH_PE_pcrel 0x10
+#define DW_GNU_EH_PE_textrel 0x20
+#define DW_GNU_EH_PE_datarel 0x30
+#define DW_GNU_EH_PE_funcrel 0x40
+#define DW_GNU_EH_PE_aligned 0x50
+#define DW_GNU_EH_PE_indirect 0x80
+#define DW_GNU_EH_PE_omit 0xFF
+
+#endif // DebugBase_dwarf_h_
diff --git a/lldb/include/lldb/Expression/ClangASTSource.h b/lldb/include/lldb/Expression/ClangASTSource.h
new file mode 100644
index 00000000000..4f1e5631525
--- /dev/null
+++ b/lldb/include/lldb/Expression/ClangASTSource.h
@@ -0,0 +1,67 @@
+/*
+ * ClangASTSource.h
+ * lldb
+ *
+ * Created by John McCall on 6/1/10.
+ * Copyright 2010 Apple. All rights reserved.
+ *
+ */
+#ifndef liblldb_ClangASTSource_h_
+#define liblldb_ClangASTSource_h_
+
+#include "clang/Sema/ExternalSemaSource.h"
+
+namespace lldb_private {
+
+class ClangExpressionDeclMap;
+
+class ClangASTSource : public clang::ExternalSemaSource {
+ clang::ASTContext &Context;
+ ClangExpressionDeclMap &DeclMap;
+public:
+ friend struct NameSearchContext;
+
+ ClangASTSource(clang::ASTContext &Context,
+ ClangExpressionDeclMap &DeclMap) :
+ Context(Context),
+ DeclMap(DeclMap) {}
+ ~ClangASTSource();
+
+ clang::Decl *GetExternalDecl(uint32_t);
+ clang::Stmt *GetExternalDeclStmt(uint64_t);
+
+ clang::Selector GetExternalSelector(uint32_t);
+ uint32_t GetNumExternalSelectors();
+
+ clang::DeclContext::lookup_result FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
+ clang::DeclarationName Name);
+
+ bool FindExternalLexicalDecls(const clang::DeclContext *DC,
+ llvm::SmallVectorImpl<clang::Decl*> &Decls);
+
+ void StartTranslationUnit(clang::ASTConsumer *Consumer);
+};
+
+// API for ClangExpressionDeclMap
+struct NameSearchContext {
+ ClangASTSource &ASTSource;
+ llvm::SmallVectorImpl<clang::NamedDecl*> &Decls;
+ clang::DeclarationName &Name;
+ const clang::DeclContext *DC;
+
+ NameSearchContext (ClangASTSource &ASTSource,
+ llvm::SmallVectorImpl<clang::NamedDecl*> &Decls,
+ clang::DeclarationName &Name,
+ const clang::DeclContext *DC) :
+ ASTSource(ASTSource),
+ Decls(Decls),
+ Name(Name),
+ DC(DC) {}
+
+ clang::ASTContext *GetASTContext();
+ clang::NamedDecl *AddVarDecl(void *type);
+};
+
+}
+
+#endif \ No newline at end of file
diff --git a/lldb/include/lldb/Expression/ClangExpression.h b/lldb/include/lldb/Expression/ClangExpression.h
new file mode 100644
index 00000000000..a645abf8829
--- /dev/null
+++ b/lldb/include/lldb/Expression/ClangExpression.h
@@ -0,0 +1,124 @@
+//===-- 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>
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "llvm/ExecutionEngine/JITMemoryManager.h"
+
+namespace llvm
+{
+ class ExecutionEngine;
+ class StringRef;
+}
+
+namespace lldb_private {
+
+class RecordingMemoryManager;
+
+class ClangExpression
+{
+public:
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ClangExpression(const char *target_triple,
+ ClangExpressionDeclMap *expr_decl_map);
+
+ ~ClangExpression();
+
+ unsigned Compile();
+
+ unsigned
+ ParseExpression (const char *expr_text, Stream &stream);
+
+ unsigned
+ ParseBareExpression (llvm::StringRef expr_text, Stream &stream);
+
+ unsigned
+ ConvertExpressionToDWARF (ClangExpressionVariableList &expr_local_variable_list,
+ StreamString &dwarf_opcode_strm);
+
+ bool
+ JITFunction (const ExecutionContext &exc_context, const char *func_name);
+
+ bool
+ WriteJITCode (const ExecutionContext &exc_context);
+
+ lldb::addr_t
+ GetFunctionAddress (const char *name);
+
+ clang::CompilerInstance *
+ GetCompilerInstance ()
+ {
+ return m_clang_ap.get();
+ }
+
+ clang::ASTContext *
+ GetASTContext ();
+
+ static Mutex &
+ GetClangMutex ();
+protected:
+
+ // This class is a pass-through for the default JIT memory manager,
+ // which just records the memory regions that were handed out so we
+ // can copy them into the target later on.
+
+
+ //------------------------------------------------------------------
+ // Classes that inherit from ClangExpression can see and modify these
+ //------------------------------------------------------------------
+
+ struct JittedFunction {
+ std::string m_name;
+ lldb::addr_t m_local_addr;
+ lldb::addr_t m_remote_addr;
+
+ 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) {}
+ };
+
+ std::string m_target_triple;
+ ClangExpressionDeclMap *m_decl_map;
+ std::auto_ptr<clang::CompilerInstance> m_clang_ap;
+ clang::CodeGenerator *m_code_generator_ptr; // This will be deleted by the Execution Engine.
+ RecordingMemoryManager *m_jit_mm_ptr; // This will be deleted by the Execution Engine.
+ std::auto_ptr<llvm::ExecutionEngine> m_execution_engine;
+ std::vector<JittedFunction> m_jitted_functions;
+private:
+
+ bool CreateCompilerInstance(bool &IsAST);
+
+ //------------------------------------------------------------------
+ // For ClangExpression only
+ //------------------------------------------------------------------
+ ClangExpression(const ClangExpression&);
+ const ClangExpression& operator=(const ClangExpression&);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangExpression_h_
diff --git a/lldb/include/lldb/Expression/ClangExpressionDeclMap.h b/lldb/include/lldb/Expression/ClangExpressionDeclMap.h
new file mode 100644
index 00000000000..e1c9dc4ebc3
--- /dev/null
+++ b/lldb/include/lldb/Expression/ClangExpressionDeclMap.h
@@ -0,0 +1,71 @@
+//===-- 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 "lldb/Core/ClangForward.h"
+#include "lldb/Core/Value.h"
+
+namespace clang {
+ class DeclarationName;
+ class DeclContext;
+}
+
+namespace lldb_private {
+
+class NameSearchContext;
+class Variable;
+
+class ClangExpressionDeclMap
+{
+public:
+ ClangExpressionDeclMap(ExecutionContext *exe_ctx);
+ ~ClangExpressionDeclMap();
+
+ // Interface for ClangStmtVisitor
+ bool GetIndexForDecl (uint32_t &index,
+ const clang::Decl *decl);
+
+ // Interface for DwarfExpression
+ Value *GetValueForIndex (uint32_t index);
+
+ // Interface for ClangASTSource
+ void GetDecls (NameSearchContext &context,
+ const char *name);
+protected:
+private:
+ struct Tuple
+ {
+ const clang::NamedDecl *m_decl;
+ Value *m_value; /* owned by ClangExpressionDeclMap */
+ };
+
+ typedef std::vector<Tuple> TupleVector;
+ typedef TupleVector::iterator TupleIterator;
+
+ TupleVector m_tuples;
+ ExecutionContext *m_exe_ctx;
+ SymbolContext *m_sym_ctx; /* owned by ClangExpressionDeclMap */
+
+ void AddOneVariable(NameSearchContext &context, Variable* var);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangExpressionDeclMap_h_
diff --git a/lldb/include/lldb/Expression/ClangExpressionVariable.h b/lldb/include/lldb/Expression/ClangExpressionVariable.h
new file mode 100644
index 00000000000..fc6cccced11
--- /dev/null
+++ b/lldb/include/lldb/Expression/ClangExpressionVariable.h
@@ -0,0 +1,58 @@
+//===-- 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>
+
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/Value.h"
+
+namespace lldb_private {
+
+class ClangExpressionVariableList
+{
+public:
+ ClangExpressionVariableList();
+ ~ClangExpressionVariableList();
+
+ Value *
+ GetVariableForVarDecl (clang::ASTContext &ast_context,
+ const clang::VarDecl *var_decl,
+ uint32_t& idx,
+ bool can_create);
+
+ Value *
+ GetVariableAtIndex (uint32_t idx);
+
+ uint32_t
+ AppendValue (Value *value); // takes ownership
+
+private:
+ struct ClangExpressionVariable
+ {
+ const clang::VarDecl *m_var_decl;
+ Value *m_value;
+ };
+
+ typedef std::vector<ClangExpressionVariable> Variables;
+ Variables m_variables;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangExpressionVariable_h_
diff --git a/lldb/include/lldb/Expression/ClangFunction.h b/lldb/include/lldb/Expression/ClangFunction.h
new file mode 100644
index 00000000000..bf0a8172067
--- /dev/null
+++ b/lldb/include/lldb/Expression/ClangFunction.h
@@ -0,0 +1,241 @@
+//===-- 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/lldb.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectList.h"
+
+#include "lldb/Expression/ClangExpression.h"
+
+// Right now, this is just a toy. It calls a set function, with fixed
+// values.
+
+namespace clang
+{
+ class ASTRecordLayout;
+}
+
+namespace lldb_private
+{
+
+class ClangFunction : private ClangExpression
+{
+public:
+
+ typedef enum ExecutionResults
+ {
+ eExecutionSetupError,
+ eExecutionCompleted,
+ eExecutionDiscarded,
+ eExecutionInterrupted,
+ eExecutionTimedOut
+ };
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ // Usage Note:
+
+ // A given ClangFunction object can handle any function with a common signature. It can also be used to
+ // set up any number of concurrent functions calls once it has been constructed.
+ // When you construct it you pass in a particular function, information sufficient to determine the function signature
+ // and value list.
+ // The simplest use of the ClangFunction is to construct the function, then call ExecuteFunction (context, errors, results). The function
+ // will be called using the initial arguments, and the results determined for you, and all cleanup done.
+ //
+ // However, if you need to use the function caller in Thread Plans, you need to call the function on the plan stack.
+ // In that case, you call GetThreadPlanToCallFunction, args_addr will be the location of the args struct, and after you are
+ // done running this thread plan you can recover the results using FetchFunctionResults passing in the same value.
+ // You are required to call InsertFunction before calling GetThreadPlanToCallFunction.
+ //
+ // You can also reuse the struct if you want, by calling ExecuteFunction but passing in args_addr_ptr primed to this value.
+ //
+ // You can also reuse the ClangFunction for the same signature but different function or argument values by rewriting the
+ // Functions arguments with WriteFunctionArguments, and then calling ExecuteFunction passing in the same args_addr.
+ //
+ // Note, any of the functions below 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 functions below that take arg_addr_ptr can be passed NULL, and the argument space will be managed for you.
+
+ ClangFunction(const char *target_triple, Function &function_ptr, ClangASTContext *ast_context, const ValueList &arg_value_list);
+ // This constructor takes its return type as a Clang QualType opaque pointer, and the ast_context it comes from.
+ // FIXME: We really should be able to easily make a Type from the qualtype, and then just pass that in.
+ ClangFunction(const char *target_triple, ClangASTContext *ast_context, void *return_qualtype, const Address& functionAddress, const ValueList &arg_value_list);
+ virtual ~ClangFunction();
+
+ unsigned CompileFunction (Stream &errors);
+
+ // args_addr is a pointer to the address the addr will be filled with. If the value on
+ // input is LLDB_INVALID_ADDRESS then a new address will be allocated, and returned in args_addr.
+ // If args_addr is a value already returned from a previous call to InsertFunction, then
+ // the args structure at that address is overwritten.
+ // If any other value is returned, then we return false, and do nothing.
+ bool InsertFunction (ExecutionContext &context, lldb::addr_t &args_addr_ref, Stream &errors);
+
+ bool WriteFunctionWrapper (ExecutionContext &exec_ctx, Stream &errors);
+
+ // This variant writes down the original function address and values to args_addr.
+ bool WriteFunctionArguments (ExecutionContext &exec_ctx, lldb::addr_t &args_addr_ref, Stream &errors);
+
+ // This variant writes down function_address and arg_value.
+ bool WriteFunctionArguments (ExecutionContext &exc_context, lldb::addr_t &args_addr_ref, Address function_address, ValueList &arg_values, Stream &errors);
+
+ //------------------------------------------------------------------
+ /// 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] context
+ /// 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 &context, 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] context
+ /// 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 &exc_context, 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 single_thread_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] context
+ /// The thread & process in which this function will run.
+ ///
+ /// @param[in] errors
+ /// Errors will be written here if there are any.
+ ///
+ /// @param[in] single_thread_timeout_usec
+ /// If \b true, run only this thread, if \b false let all threads run.
+ ///
+ /// @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 &context, 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] context
+ /// 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] single_thread_timeout_usec
+ /// If \b true, run only this thread, if \b false let all threads run.
+ ///
+ /// @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 &context, lldb::addr_t *args_addr_ptr, Stream &errors, bool stop_others, uint32_t single_thread_timeout_usec, bool try_all_threads, Value &results);
+ ExecutionResults ExecuteFunctionWithABI(ExecutionContext &context, Stream &errors, Value &results);
+
+ ThreadPlan *GetThreadPlanToCallFunction (ExecutionContext &exc_context, lldb::addr_t &args_addr_ref, Stream &errors, bool stop_others, bool discard_on_error = true);
+ bool FetchFunctionResults (ExecutionContext &exc_context, lldb::addr_t args_addr, Value &ret_value);
+ void DeallocateFunctionResults (ExecutionContext &exc_context, lldb::addr_t args_addr);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from ClangFunction can see and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For ClangFunction only
+ //------------------------------------------------------------------
+
+ 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.
+ void *m_function_return_qual_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;
+ std::string m_wrapper_struct_name;
+ const clang::ASTRecordLayout *m_struct_layout;
+ ValueList m_arg_values;
+ lldb::addr_t m_wrapper_fun_addr;
+ std::list<lldb::addr_t> m_wrapper_args_addrs;
+
+ size_t m_value_struct_size;
+ size_t m_return_offset;
+ uint64_t m_return_size; // Not strictly necessary, could get it from the Function...
+ bool m_compiled;
+ bool m_JITted;
+};
+
+}; // Namespace lldb_private
+#endif // lldb_ClangFunction_h_
diff --git a/lldb/include/lldb/Expression/ClangStmtVisitor.h b/lldb/include/lldb/Expression/ClangStmtVisitor.h
new file mode 100644
index 00000000000..5f8d6e5936f
--- /dev/null
+++ b/lldb/include/lldb/Expression/ClangStmtVisitor.h
@@ -0,0 +1,109 @@
+//===-- ClangStmtVisitor.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangStmtVisitor_h_
+#define liblldb_ClangStmtVisitor_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+#include "clang/AST/StmtVisitor.h"
+
+// Project includes
+#include "lldb/Core/ClangForward.h"
+
+namespace lldb_private {
+
+class StreamString;
+class ClangExpressionDeclMap;
+class ClangExpressionVariableList;
+
+#define CLANG_STMT_RESULT void
+
+class ClangStmtVisitor : public clang::StmtVisitor<ClangStmtVisitor, CLANG_STMT_RESULT>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ClangStmtVisitor (clang::ASTContext &ast_context,
+ ClangExpressionVariableList &variable_list,
+ ClangExpressionDeclMap *decl_map,
+ StreamString &strm);
+ virtual ~ClangStmtVisitor ();
+
+ // Stmts.
+ CLANG_STMT_RESULT VisitStmt (clang::Stmt *Node);
+ CLANG_STMT_RESULT VisitDeclStmt (clang::DeclStmt *Node);
+ CLANG_STMT_RESULT VisitLabelStmt (clang::LabelStmt *Node);
+ CLANG_STMT_RESULT VisitGotoStmt (clang::GotoStmt *Node);
+
+ // Exprs
+ CLANG_STMT_RESULT VisitExpr (clang::Expr *Node);
+ CLANG_STMT_RESULT VisitDeclRefExpr (clang::DeclRefExpr *Node);
+ CLANG_STMT_RESULT VisitPredefinedExpr (clang::PredefinedExpr *Node);
+ CLANG_STMT_RESULT VisitCharacterLiteral (clang::CharacterLiteral *Node);
+ CLANG_STMT_RESULT VisitIntegerLiteral (clang::IntegerLiteral *Node);
+ CLANG_STMT_RESULT VisitFloatingLiteral (clang::FloatingLiteral *Node);
+ CLANG_STMT_RESULT VisitStringLiteral (clang::StringLiteral *Str);
+ CLANG_STMT_RESULT VisitUnaryOperator (clang::UnaryOperator *Node);
+ CLANG_STMT_RESULT VisitSizeOfAlignOfExpr (clang::SizeOfAlignOfExpr *Node);
+ CLANG_STMT_RESULT VisitMemberExpr (clang::MemberExpr *Node);
+ CLANG_STMT_RESULT VisitExtVectorElementExpr (clang::ExtVectorElementExpr *Node);
+ CLANG_STMT_RESULT VisitBinaryOperator (clang::BinaryOperator *Node);
+// CLANG_STMT_RESULT VisitCompoundAssignOperator (clang::CompoundAssignOperator *Node);
+ CLANG_STMT_RESULT VisitAddrLabelExpr (clang::AddrLabelExpr *Node);
+ CLANG_STMT_RESULT VisitTypesCompatibleExpr (clang::TypesCompatibleExpr *Node);
+ CLANG_STMT_RESULT VisitParenExpr(clang::ParenExpr *Node);
+ CLANG_STMT_RESULT VisitInitListExpr (clang::InitListExpr *Node);
+ CLANG_STMT_RESULT VisitCastExpr (clang::CastExpr *Node);
+// CLANG_STMT_RESULT VisitImplicitCastExpr (clang::ImplicitCastExpr *Node);
+ CLANG_STMT_RESULT VisitArraySubscriptExpr (clang::ArraySubscriptExpr *Node);
+ // C++
+ CLANG_STMT_RESULT VisitCXXNamedCastExpr (clang::CXXNamedCastExpr *Node);
+ CLANG_STMT_RESULT VisitCXXBoolLiteralExpr (clang::CXXBoolLiteralExpr *Node);
+ CLANG_STMT_RESULT VisitCXXThisExpr (clang::CXXThisExpr *Node);
+ CLANG_STMT_RESULT VisitCXXFunctionalCastExpr (clang::CXXFunctionalCastExpr *Node);
+
+ // ObjC
+ CLANG_STMT_RESULT VisitObjCEncodeExpr (clang::ObjCEncodeExpr *Node);
+ CLANG_STMT_RESULT VisitObjCMessageExpr (clang::ObjCMessageExpr* Node);
+ CLANG_STMT_RESULT VisitObjCSelectorExpr (clang::ObjCSelectorExpr *Node);
+ CLANG_STMT_RESULT VisitObjCProtocolExpr (clang::ObjCProtocolExpr *Node);
+ CLANG_STMT_RESULT VisitObjCPropertyRefExpr (clang::ObjCPropertyRefExpr *Node);
+ CLANG_STMT_RESULT VisitObjCImplicitSetterGetterRefExpr (clang::ObjCImplicitSetterGetterRefExpr *Node);
+ CLANG_STMT_RESULT VisitObjCIvarRefExpr (clang::ObjCIvarRefExpr *Node);
+ CLANG_STMT_RESULT VisitObjCSuperExpr (clang::ObjCSuperExpr *Node);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from ClangStmtVisitor can see and modify these
+ //------------------------------------------------------------------
+ clang::ASTContext &m_ast_context;
+ ClangExpressionDeclMap *m_decl_map;
+ ClangExpressionVariableList &m_variable_list;
+ StreamString &m_stream;
+private:
+ //------------------------------------------------------------------
+ // For ClangStmtVisitor only
+ //------------------------------------------------------------------
+ ClangStmtVisitor (const ClangStmtVisitor&);
+ const ClangStmtVisitor& operator= (const ClangStmtVisitor&);
+
+ bool
+ EncodeUInt64 (uint64_t uval, uint32_t bit_size);
+
+ bool
+ EncodeSInt64 (int64_t sval, uint32_t bit_size);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangStmtVisitor_h_
diff --git a/lldb/include/lldb/Expression/DWARFExpression.h b/lldb/include/lldb/Expression/DWARFExpression.h
new file mode 100644
index 00000000000..072697659fa
--- /dev/null
+++ b/lldb/include/lldb/Expression/DWARFExpression.h
@@ -0,0 +1,126 @@
+//===-- 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"
+
+class ClangExpressionVariable;
+class ClangExpressionVariableList;
+
+namespace lldb_private {
+
+class ClangExpressionDeclMap;
+
+//----------------------------------------------------------------------
+// A class designed to evaluate the DWARF expression opcodes. We will
+// likely augment its abilities to handle features not supported by
+// the DWARF expression engine.
+//----------------------------------------------------------------------
+class DWARFExpression
+{
+public:
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ DWARFExpression();
+
+ DWARFExpression(const DataExtractor& data,
+ uint32_t data_offset,
+ uint32_t data_length,
+ const Address* loclist_base_addr_ptr);
+
+ DWARFExpression(const DWARFExpression& rhs);
+
+ virtual
+ ~DWARFExpression();
+
+ void
+ GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+ bool
+ IsValid() const;
+
+ bool
+ IsLocationList() const;
+
+ bool
+ LocationListContainsLoadAddress (Process* process, const Address &addr) const;
+
+ void
+ SetOpcodeData(const DataExtractor& data, const Address* loclist_base_addr_ptr);
+
+ void
+ SetOpcodeData(const DataExtractor& data, uint32_t data_offset, uint32_t data_length, const Address* loclist_base_addr_ptr);
+
+ void
+ SetLocationListBaseAddress(Address& base_addr);
+
+ int
+ GetRegisterKind ();
+
+ void
+ SetRegisterKind (int reg_kind);
+
+ bool
+ Evaluate (ExecutionContextScope *exe_scope,
+ clang::ASTContext *ast_context,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr) const;
+
+ bool
+ Evaluate (ExecutionContext *exe_ctx,
+ clang::ASTContext *ast_context,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr) const;
+
+ static bool
+ Evaluate (ExecutionContext *exe_ctx,
+ clang::ASTContext *ast_context,
+ const DataExtractor& opcodes,
+ ClangExpressionVariableList *expr_locals,
+ ClangExpressionDeclMap *decl_map,
+ const uint32_t offset,
+ const uint32_t length,
+ const uint32_t reg_set,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr);
+
+ void
+ SetExpressionLocalVariableList (ClangExpressionVariableList *locals);
+
+ void
+ SetExpressionDeclMap (ClangExpressionDeclMap *decl_map);
+
+protected:
+
+ void DumpLocation(Stream *s, uint32_t offset, uint32_t length, lldb::DescriptionLevel level) const;
+ //------------------------------------------------------------------
+ // Classes that inherit from DWARFExpression can see and modify these
+ //------------------------------------------------------------------
+ DataExtractor m_data;
+ int m_reg_kind; // One of the defines that starts with LLDB_REGKIND_
+ Address m_loclist_base_addr; // Base address needed for location lists
+ ClangExpressionVariableList *m_expr_locals;
+ ClangExpressionDeclMap *m_decl_map;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_DWARFExpression_h_
diff --git a/lldb/include/lldb/Expression/RecordingMemoryManager.h b/lldb/include/lldb/Expression/RecordingMemoryManager.h
new file mode 100644
index 00000000000..8ebc08e1158
--- /dev/null
+++ b/lldb/include/lldb/Expression/RecordingMemoryManager.h
@@ -0,0 +1,154 @@
+//===-- RecordingMemoryManager.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_RecordingMemoryManager_h_
+#define lldb_RecordingMemoryManager_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <vector>
+#include <map>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "llvm/ExecutionEngine/JITMemoryManager.h"
+#include "lldb/Expression/ClangExpression.h"
+
+namespace lldb_private {
+
+class RecordingMemoryManager : public llvm::JITMemoryManager
+{
+
+// I can't write the JIT code in this class because this class has to be
+// built without RTTI, which means I can't include Process.h. But I don't
+// want to write iterators or "do_over_regions" functions right now, so I'm
+// just going to let the ClangExpression handle it using our data members directly.
+
+friend bool ClangExpression::WriteJITCode (const ExecutionContext &exc_context);
+
+public:
+ RecordingMemoryManager ();
+ virtual ~RecordingMemoryManager();
+
+ virtual void setMemoryWritable ();
+
+ virtual void setMemoryExecutable ();
+
+ virtual void setPoisonMemory (bool poison)
+ {
+ m_default_mm_ap->setPoisonMemory (poison);
+ }
+
+ virtual void AllocateGOT()
+ {
+ m_default_mm_ap->AllocateGOT();
+ }
+
+
+ virtual uint8_t *getGOTBase() const
+ {
+ return m_default_mm_ap->getGOTBase();
+ }
+
+ virtual uint8_t *startFunctionBody(const llvm::Function *F,
+ uintptr_t &ActualSize);
+
+ virtual uint8_t *allocateStub(const llvm::GlobalValue* F, unsigned StubSize,
+ unsigned Alignment);
+
+ virtual void endFunctionBody(const llvm::Function *F, uint8_t *FunctionStart,
+ uint8_t *FunctionEnd);
+
+ virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment);
+
+ virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment);
+
+ virtual void deallocateFunctionBody(void *Body);
+
+ virtual uint8_t* startExceptionTable(const llvm::Function* F,
+ uintptr_t &ActualSize);
+
+ virtual void endExceptionTable(const llvm::Function *F, uint8_t *TableStart,
+ uint8_t *TableEnd, uint8_t* FrameRegister);
+
+ virtual void deallocateExceptionTable(void *ET);
+
+ virtual size_t GetDefaultCodeSlabSize() {
+ return m_default_mm_ap->GetDefaultCodeSlabSize();
+ }
+
+ virtual size_t GetDefaultDataSlabSize() {
+ return m_default_mm_ap->GetDefaultDataSlabSize();
+ }
+
+ virtual size_t GetDefaultStubSlabSize() {
+ return m_default_mm_ap->GetDefaultStubSlabSize();
+ }
+
+ virtual unsigned GetNumCodeSlabs() {
+ return m_default_mm_ap->GetNumCodeSlabs();
+ }
+
+ virtual unsigned GetNumDataSlabs() {
+ return m_default_mm_ap->GetNumDataSlabs();
+ }
+
+ virtual unsigned GetNumStubSlabs() {
+ return m_default_mm_ap->GetNumStubSlabs();
+ }
+
+ // These are methods I've added so we can transfer the memory we've remembered down
+ // to the target program. For now I'm assuming all this code is PIC without fixups,
+ // so I'll just copy it blind, but if we need to we can do fixups later.
+
+ lldb::addr_t
+ GetRemoteAddressForLocal (lldb::addr_t local_address);
+
+ bool
+ WriteJITRegions (const ExecutionContext &exc_context);
+
+
+private:
+ std::auto_ptr<JITMemoryManager> m_default_mm_ap;
+ std::map<uint8_t *, uint8_t *> m_functions;
+ std::map<uint8_t *, intptr_t> m_spaceBlocks;
+ std::map<uint8_t *, unsigned> m_stubs;
+ std::map<uint8_t *, uintptr_t> m_globals;
+ std::map<uint8_t *, uint8_t *> m_exception_tables;
+
+ struct LocalToRemoteAddressRange
+ {
+ lldb::addr_t m_local_start;
+ size_t m_size;
+ lldb::addr_t m_remote_start;
+
+ LocalToRemoteAddressRange (lldb::addr_t lstart, size_t size, lldb::addr_t rstart) :
+ m_local_start (lstart),
+ m_size (size),
+ m_remote_start (rstart)
+ {}
+
+ };
+
+ void
+ AddToLocalToRemoteMap (lldb::addr_t lstart, size_t size, lldb::addr_t rstart);
+
+ // We should probably store this by address so we can efficiently
+ // search it but there really won't be many elements in this array
+ // at present. So we can put that off for now.
+ std::vector<LocalToRemoteAddressRange> m_address_map;
+
+};
+
+}; // namespace lldb_private
+#endif // lldb_RecordingMemoryManager_h_
diff --git a/lldb/include/lldb/Host/Condition.h b/lldb/include/lldb/Host/Condition.h
new file mode 100644
index 00000000000..5ae50ae3fac
--- /dev/null
+++ b/lldb/include/lldb/Host/Condition.h
@@ -0,0 +1,123 @@
+//===-- 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>
+
+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 ();
+
+ //------------------------------------------------------------------
+ /// Get accessor to the pthread condition object.
+ ///
+ /// @return
+ /// A pointer to the condition variable owned by this object.
+ //------------------------------------------------------------------
+ pthread_cond_t *
+ GetCondition ();
+
+ //------------------------------------------------------------------
+ /// 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 (pthread_mutex_t *mutex, const TimeValue *abstime = NULL, bool *timed_out = NULL);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ pthread_cond_t m_condition; ///< The condition variable.
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif
+
diff --git a/lldb/include/lldb/Host/Endian.h b/lldb/include/lldb/Host/Endian.h
new file mode 100644
index 00000000000..5d1e848ef31
--- /dev/null
+++ b/lldb/include/lldb/Host/Endian.h
@@ -0,0 +1,19 @@
+//===-- 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_
+
+// TODO: come up with a more lldb specific solution instead of relying on
+// macosx <machine/endian.h>....
+
+#include <machine/endian.h>
+
+#endif // liblldb_host_endian_h_
+
diff --git a/lldb/include/lldb/Host/Host.h b/lldb/include/lldb/Host/Host.h
new file mode 100644
index 00000000000..5f52085ae6d
--- /dev/null
+++ b/lldb/include/lldb/Host/Host.h
@@ -0,0 +1,281 @@
+//===-- 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 "lldb/lldb-private.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,
+ 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 unique handle to the process monitoring information that
+ /// can be used to stop monitoring a child process.
+ ///
+ /// @see static void Host::StopMonitoringChildProcess (uint32_t)
+ //------------------------------------------------------------------
+ static uint32_t
+ StartMonitoringChildProcess (MonitorChildProcessCallback callback,
+ void *callback_baton,
+ lldb::pid_t pid,
+ bool monitor_signals);
+
+ //------------------------------------------------------------------
+ /// Stop monitoring a child process.
+ ///
+ /// @param[in] handle
+ /// A unique handle returned from a previous call to
+ /// Host::StartMonitoringChildProcess(...).
+ ///
+ /// @return
+ /// \b true if the the handle was found and disabled, \b false
+ /// if the monitor map with handle of \a handle was not found.
+ ///
+ /// @see static int Host::StartMonitoringChildProcess (MonitorChildProcessCallback *, void *, lldb::pid_t, bool)
+ //------------------------------------------------------------------
+ static bool
+ StopMonitoringChildProcess (uint32_t handle);
+
+ //------------------------------------------------------------------
+ /// 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 ();
+
+ //------------------------------------------------------------------
+ /// Gets the host kernel architecture.
+ ///
+ /// @return
+ /// A const architecture object that represents the host kernel
+ /// architecture.
+ //------------------------------------------------------------------
+ static const ArchSpec &
+ GetArchitecture ();
+
+ //------------------------------------------------------------------
+ /// 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::pid_t
+ GetCurrentThreadID ();
+
+ 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 NULL terminate C string name that is owned by a static
+ /// global string pool, or NULL if there is no matching thread
+ /// name. This string does not need to be freed.
+ //------------------------------------------------------------------
+ static const char *
+ 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 void
+ SetThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name);
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ static bool
+ ResolveExecutableInBundle (FileSpec *file);
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_Host_h_
diff --git a/lldb/include/lldb/Host/Mutex.h b/lldb/include/lldb/Host/Mutex.h
new file mode 100644
index 00000000000..19f613a86f6
--- /dev/null
+++ b/lldb/include/lldb/Host/Mutex.h
@@ -0,0 +1,242 @@
+//===-- 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>
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Mutex Mutex.h "lldb/Host/Mutex.h"
+/// @brief A C++ wrapper class for pthread mutexes.
+//----------------------------------------------------------------------
+class Mutex
+{
+public:
+ 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);
+
+ //--------------------------------------------------------------
+ /// Constructor with a raw pthread mutex object pointer.
+ ///
+ /// This will create a scoped mutex locking object that locks
+ /// \a mutex.
+ ///
+ /// @param[in] mutex
+ /// A pointer to a pthread_mutex_t that will get locked if
+ /// non-NULL.
+ //--------------------------------------------------------------
+ Locker(pthread_mutex_t *mutex);
+
+ //--------------------------------------------------------------
+ /// 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
+ Reset(pthread_mutex_t *mutex = NULL);
+
+ //--------------------------------------------------------------
+ /// 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 (pthread_mutex_t *mutex);
+
+ protected:
+ //--------------------------------------------------------------
+ /// Member variables
+ //--------------------------------------------------------------
+ pthread_mutex_t *m_mutex_ptr; ///< A pthread mutex that is locked when
+ ///< acquired and unlocked when destroyed
+ ///< or reset.
+
+ 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.
+ //------------------------------------------------------------------
+ ~Mutex();
+
+ //------------------------------------------------------------------
+ /// Mutex get accessor.
+ ///
+ /// @return
+ /// A pointer to the pthread mutex object owned by this object.
+ //------------------------------------------------------------------
+ pthread_mutex_t *
+ GetMutex();
+
+ //------------------------------------------------------------------
+ /// 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().
+ //------------------------------------------------------------------
+ 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().
+ //------------------------------------------------------------------
+ int
+ TryLock();
+
+ //------------------------------------------------------------------
+ /// 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().
+ //------------------------------------------------------------------
+ int
+ Unlock();
+
+ static
+ int Lock (pthread_mutex_t *mutex_ptr);
+
+ static
+ int TryLock (pthread_mutex_t *mutex_ptr);
+
+ static
+ int Unlock (pthread_mutex_t *mutex_ptr);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ pthread_mutex_t m_mutex; ///< The pthread mutex object.
+private:
+ Mutex(const Mutex&);
+ const Mutex& operator=(const Mutex&);
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif
diff --git a/lldb/include/lldb/Host/Predicate.h b/lldb/include/lldb/Host/Predicate.h
new file mode 100644
index 00000000000..9c3f10bceae
--- /dev/null
+++ b/lldb/include/lldb/Host/Predicate.h
@@ -0,0 +1,411 @@
+//===-- 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_mutex(),
+ m_condition(),
+ m_value()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// 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_mutex(),
+ m_condition(),
+ m_value(initial_value)
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// 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)", __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)", __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)", __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.
+ ///
+ /// @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", __FUNCTION__, bits, abstime, m_value);
+#endif
+ while (err == 0 && ((m_value & bits) == 0))
+ {
+ err = m_condition.Wait (m_mutex.GetMutex(), abstime);
+ }
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x, returning 0x%8.8x", __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.
+ ///
+ /// @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", __FUNCTION__, bits, abstime, m_value);
+#endif
+ while (err == 0 && (m_value & bits != 0))
+ {
+ err = m_condition.Wait (m_mutex.GetMutex(), abstime);
+ }
+
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x", __FUNCTION__, bits, m_value);
+#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.
+ ///
+ /// @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", __FUNCTION__, value, abstime, m_value);
+#endif
+ while (err == 0 && m_value != value)
+ {
+ err = m_condition.Wait (m_mutex.GetMutex(), abstime, timed_out);
+ }
+
+ return m_value == value;
+ }
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @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", __FUNCTION__, value, abstime, m_value);
+#endif
+ while (err == 0 && m_value == value)
+ {
+ err = m_condition.Wait (m_mutex.GetMutex(), 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", __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/lldb/include/lldb/Host/Symbols.h b/lldb/include/lldb/Host/Symbols.h
new file mode 100644
index 00000000000..7359dda8a6d
--- /dev/null
+++ b/lldb/include/lldb/Host/Symbols.h
@@ -0,0 +1,37 @@
+//===-- 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/Core/FileSpec.h"
+
+namespace lldb_private {
+
+class Symbols
+{
+public:
+ static FileSpec
+ LocateExecutableObjectFile (const FileSpec *in_exec, const ArchSpec* arch, const UUID *uuid);
+
+ static FileSpec
+ LocateExecutableSymbolFile (const FileSpec *in_exec, const ArchSpec* arch, const UUID *uuid);
+};
+
+} // namespace lldb_private
+
+
+#endif // liblldb_Symbols_h_
diff --git a/lldb/include/lldb/Host/TimeValue.h b/lldb/include/lldb/Host/TimeValue.h
new file mode 100644
index 00000000000..623660e2908
--- /dev/null
+++ b/lldb/include/lldb/Host/TimeValue.h
@@ -0,0 +1,90 @@
+//===-- 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>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+namespace lldb_private {
+
+class TimeValue
+{
+public:
+ //------------------------------------------------------------------
+ // 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;
+
+ struct timespec
+ GetAsTimeSpec () const;
+
+ struct timeval
+ GetAsTimeVal () const;
+
+ bool
+ IsValid () const;
+
+ void
+ OffsetWithSeconds (uint32_t sec);
+
+ void
+ OffsetWithMicroSeconds (uint32_t usec);
+
+ void
+ OffsetWithNanoSeconds (uint32_t nsec);
+
+ static TimeValue
+ Now();
+
+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/lldb/include/lldb/Host/Types.h b/lldb/include/lldb/Host/Types.h
new file mode 100644
index 00000000000..1fa791cf692
--- /dev/null
+++ b/lldb/include/lldb/Host/Types.h
@@ -0,0 +1,98 @@
+//===-- Types.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#if 0
+#ifndef liblldb_host_types_h_
+#define liblldb_host_types_h_
+
+//----------------------------------------------------------------------
+//----------------------------------------------------------------------
+// MACOSX START
+//----------------------------------------------------------------------
+//----------------------------------------------------------------------
+
+#include <assert.h>
+#include <mach/mach_types.h>
+#include <machine/endian.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/syslimits.h>
+#include <unistd.h>
+
+#ifndef NO_RTTI
+
+//----------------------------------------------------------------------
+// And source files that may not have RTTI enabled during their
+// compilation will want to do a "#define NO_RTTI" before including the
+// lldb-include.h file.
+//----------------------------------------------------------------------
+
+#include <tr1/memory> // for std::tr1::shared_ptr
+
+#endif
+
+//----------------------------------------------------------------------
+// All host systems must define:
+// liblldb::condition_t The native condition type (or a substitute class) for conditions on the host system.
+// liblldb::mutex_t The native mutex type for mutex objects on the host system.
+// liblldb::thread_t The native thread type for spawned threads on the system
+// liblldb::thread_arg_t The type of the one any only thread creation argument for the host system
+// liblldb::thread_result_t The return type that gets returned when a thread finishes.
+// liblldb::thread_func_t The function prototype used to spawn a thread on the host system.
+// liblldb::SharedPtr The template that wraps up the host version of a reference counted pointer (like boost::shared_ptr)
+// #define LLDB_INVALID_PROCESS_ID ...
+// #define LLDB_INVALID_THREAD_ID ...
+// #define LLDB_INVALID_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_private {
+ //----------------------------------------------------------------------
+ // 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
+
+#ifndef NO_RTTI
+ // The template below can be used in a few useful ways:
+ //
+ // // Make a single shared pointer a class Foo
+ // lldb::SharePtr<Foo>::Type foo_sp;
+ //
+ // // Make a typedef to a Foo shared pointer
+ // typedef lldb::SharePtr<Foo>::Type FooSP;
+ //
+ template<typename _Tp>
+ struct SharedPtr
+ {
+ typedef std::tr1::shared_ptr<_Tp> Type;
+ };
+#endif
+
+} // namespace lldb_private
+
+#define LLDB_INVALID_HOST_THREAD ((lldb::thread_t)NULL)
+#define LLDB_INVALID_HOST_TIME { 0, 0 }
+
+//----------------------------------------------------------------------
+//----------------------------------------------------------------------
+// MACOSX END
+//----------------------------------------------------------------------
+//----------------------------------------------------------------------
+
+#endif // liblldb_host_types_h_
+#endif
diff --git a/lldb/include/lldb/Interpreter/CommandCompletions.h b/lldb/include/lldb/Interpreter/CommandCompletions.h
new file mode 100644
index 00000000000..98cba48f08a
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/CommandCompletions.h
@@ -0,0 +1,240 @@
+//===-- 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
+// 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) (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::CommandInterpreter *interpreter, // The command interpreter running this command.
+ lldb_private::SearchFilter *searcher, // A search filter to limit the search...
+ lldb_private::StringList &matches); // The array of matches we return.
+ typedef enum
+ {
+ eNoCompletion = 0,
+ eSourceFileCompletion = (1 << 0),
+ eDiskFileCompletion = (1 << 1),
+ eSymbolCompletion = (1 << 2),
+ eModuleCompletion = (1 << 3),
+ eCustomCompletion = (1 << 4) // 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.
+
+ } CommonCompletionTypes;
+
+ struct CommonCompletionElement
+ {
+ CommonCompletionTypes type;
+ CompletionCallback callback;
+ };
+
+ static bool InvokeCommonCompletionCallbacks (uint32_t completion_mask,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ lldb_private::CommandInterpreter *interpreter,
+ SearchFilter *searcher,
+ StringList &matches);
+
+ //----------------------------------------------------------------------
+ // These are the generic completer functions:
+ //----------------------------------------------------------------------
+ static int
+ SourceFiles (const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ SearchFilter *searcher,
+ StringList &matches);
+
+ static int
+ Modules (const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ lldb_private::CommandInterpreter *interpreter,
+ SearchFilter *searcher,
+ lldb_private::StringList &matches);
+
+ static int
+ Symbols (const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ lldb_private::CommandInterpreter *interpreter,
+ SearchFilter *searcher,
+ 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 (const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ 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:
+ std::string m_completion_str;
+ int m_match_start_point;
+ int m_max_return_elements;
+ CommandInterpreter *m_interpreter;
+ StringList &m_matches;
+ private:
+ DISALLOW_COPY_AND_ASSIGN (Completer);
+ };
+
+ //----------------------------------------------------------------------
+ // SouceFileCompleter implements the source file completer
+ //----------------------------------------------------------------------
+ class SourceFileCompleter : public Completer
+ {
+ public:
+
+ SourceFileCompleter (bool include_support_files,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ 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 (const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ 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 (const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ 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, NameCmp> 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/lldb/include/lldb/Interpreter/CommandContext.h b/lldb/include/lldb/Interpreter/CommandContext.h
new file mode 100644
index 00000000000..69bd27e2472
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/CommandContext.h
@@ -0,0 +1,43 @@
+//===-- CommandContext.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandContext_h_
+#define liblldb_CommandContext_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/ValueObjectList.h"
+
+namespace lldb_private {
+
+class CommandContext
+{
+public:
+ CommandContext ();
+
+ ~CommandContext ();
+
+ void
+ Update (ExecutionContext *override_context = NULL);
+
+ Target *
+ GetTarget();
+
+ ExecutionContext &
+ GetExecutionContext();
+
+private:
+ ExecutionContext m_exe_ctx;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandContext_h_
diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h
new file mode 100644
index 00000000000..933fce47ff0
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h
@@ -0,0 +1,264 @@
+//===-- 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/Log.h"
+#include "lldb/Interpreter/CommandContext.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Interpreter/StateVariable.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/Args.h"
+#include "lldb/Core/StringList.h"
+
+namespace lldb_private {
+
+class CommandInterpreter : public Broadcaster
+{
+public:
+ typedef std::map<std::string, lldb::StateVariableSP> VariableMap;
+ typedef std::map<std::string, OptionArgVectorSP> OptionArgMap;
+
+ enum
+ {
+ eBroadcastBitThreadShouldExit = (1 << 0),
+ eBroadcastBitResetPrompt = (1 << 1),
+ eBroadcastBitQuitCommandReceived = (1 << 2) // User entered quit
+ };
+
+ void
+ SourceInitFile (bool in_cwd, CommandReturnObject &result);
+
+ CommandInterpreter (lldb::ScriptLanguage script_language,
+ bool synchronous_execution,
+ Listener *listener, // In case this is asked to create or attach to a process
+ SourceManager& source_manager);
+
+ virtual
+ ~CommandInterpreter ();
+
+ lldb::CommandObjectSP
+ GetCommandSP (const char *cmd, bool include_aliases = true, bool exact = true, StringList *matches = NULL);
+
+ CommandObject *
+ GetCommandObject (const char *cmd, bool include_aliases = true, bool exact = true, StringList *matches = NULL);
+
+ StateVariable *
+ GetStateVariable(const char *name);
+
+ 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
+ RemoveUser (const char *alias_name);
+
+ OptionArgVectorSP
+ GetAliasOptions (const char *alias_name);
+
+ void
+ RemoveAliasOptions (const char *alias_name);
+
+ void
+ AddOrReplaceAliasOptions (const char *alias_name, OptionArgVectorSP &option_arg_vector_sp);
+
+ bool
+ HandleCommand (const char *command_line, bool add_to_history, CommandReturnObject &result,
+ ExecutionContext *override_context = NULL);
+
+ // 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 Args 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 the total number of completions, or -1 if the completion character should be inserted, or
+ // INT_MAX if the number of matches is > max_return_elements, but it is expensive to compute.
+ //
+ // 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.
+
+ int
+ HandleCompletionMatches (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches);
+
+
+ int
+ GetCommandNamesMatchingPartialString (const char *cmd_cstr, bool include_aliases, StringList &matches);
+
+ void
+ GetHelp (CommandReturnObject &result);
+
+ 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,
+ uint32_t max_word_len);
+
+ void
+ ShowVariableValues (CommandReturnObject &result);
+
+ void
+ ShowVariableHelp (CommandReturnObject &result);
+
+ CommandContext *
+ Context();
+
+ const Args *
+ GetProgramArguments ();
+
+ const Args *
+ GetEnvironmentVariables ();
+
+ const char *
+ ProcessEmbeddedScriptCommands (const char *arg);
+
+ Listener *
+ GetListener ();
+
+ SourceManager &
+ GetSourceManager ();
+
+ const char *
+ GetPrompt ();
+
+ void
+ SetPrompt (const char *);
+
+ void
+ LoadCommandDictionary ();
+
+ void
+ Initialize ();
+
+ void
+ InitializeVariables ();
+
+ void
+ CrossRegisterCommand (const char * dest_cmd, const char * object_type);
+
+ void
+ SetScriptLanguage (lldb::ScriptLanguage lang);
+
+
+ bool
+ HasCommands ();
+
+ bool
+ HasAliases ();
+
+ bool
+ HasUserCommands ();
+
+ bool
+ HasAliasOptions ();
+
+ bool
+ HasInterpreterVariables ();
+
+ void
+ BuildAliasCommandArgs (CommandObject *alias_cmd_obj, const char *alias_name, Args &cmd_args,
+ CommandReturnObject &result);
+
+ int
+ GetOptionArgumentPosition (const char *in_string);
+
+ ScriptInterpreter *
+ GetScriptInterpreter ();
+
+ bool
+ GetSynchronous ();
+
+#ifndef SWIG
+ void
+ AddLogChannel (const char *name, const Log::Callbacks &log_callbacks);
+
+ bool
+ GetLogChannelCallbacks (const char *channel, Log::Callbacks &log_callbacks);
+
+ bool
+ RemoveLogChannel (const char *name);
+#endif
+
+ std::string
+ FindLongestCommandWord (CommandObject::CommandMap &dict);
+
+ void
+ FindCommandsForApropos (const char *word, StringList &commands_found, StringList &commands_help);
+
+ void
+ AproposAllSubCommands (CommandObject *cmd_obj, const char *prefix, const char *search_word,
+ StringList &commands_found, StringList &commands_help);
+
+protected:
+ friend class Debugger;
+
+ void
+ SetSynchronous (bool value);
+
+private:
+
+ lldb::ScriptLanguage m_script_language;
+ CommandContext m_current_context;
+ bool m_synchronous_execution;
+ Listener *m_listener;
+ SourceManager& m_source_manager;
+
+ 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
+ VariableMap m_variables;
+ OptionArgMap m_alias_options; // Stores any options (with or without arguments) that go with any alias.
+ std::vector<std::string> m_command_history;
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandInterpreter_h_
diff --git a/lldb/include/lldb/Interpreter/CommandObject.h b/lldb/include/lldb/Interpreter/CommandObject.h
new file mode 100644
index 00000000000..ae050983e34
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/CommandObject.h
@@ -0,0 +1,194 @@
+//===-- 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/Core/Args.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/Flags.h"
+
+namespace lldb_private {
+
+class CommandObject
+{
+public:
+ typedef std::map<std::string, lldb::CommandObjectSP> CommandMap;
+
+
+ CommandObject (const char *name,
+ const char *help = NULL,
+ const char *syntax = NULL,
+ uint32_t flags = 0);
+
+ virtual
+ ~CommandObject ();
+
+ const char *
+ GetHelp ();
+
+ const char *
+ GetHelpLong ();
+
+ const char *
+ GetSyntax ();
+
+ const char *
+ Translate ();
+
+ const char *
+ GetCommandName ();
+
+ void
+ SetHelp (const char * str);
+
+ void
+ SetHelpLong (const char * str);
+
+ void
+ SetSyntax (const char *str);
+
+ virtual void
+ AddObject (const char *obj_name) {}
+
+ virtual bool
+ IsCrossRefObject () { return false; }
+
+ virtual bool
+ IsMultiwordObject () { return false; }
+
+ virtual bool
+ WantsRawCommandString() { return false; }
+
+ virtual Options *
+ GetOptions ();
+
+ enum
+ {
+ eFlagProcessMustBeLaunched = (1 << 0),
+ eFlagProcessMustBePaused = (1 << 1)
+ };
+
+ // Do not override this
+ bool
+ ExecuteCommandString (const char *command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ bool
+ ParseOptions(Args& args,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ bool
+ ExecuteWithOptions (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual bool
+ ExecuteRawCommandString (const char *command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ return false;
+ }
+
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result) = 0;
+
+ 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.
+ virtual int
+ HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ 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.
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ StringList &matches);
+
+
+ bool
+ HelpTextContainsWord (const char *search_word);
+
+ //------------------------------------------------------------------
+ /// 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;
+
+protected:
+ std::string m_cmd_name;
+ std::string m_cmd_help_short;
+ std::string m_cmd_help_long;
+ std::string m_cmd_syntax;
+ Flags m_flags;
+};
+
+} // namespace lldb_private
+
+
+#endif // liblldb_CommandObject_h_
diff --git a/lldb/include/lldb/Interpreter/CommandObjectCrossref.h b/lldb/include/lldb/Interpreter/CommandObjectCrossref.h
new file mode 100644
index 00000000000..c1e8e595363
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/CommandObjectCrossref.h
@@ -0,0 +1,60 @@
+//===-- CommandObjectCrossref.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectCrossref_h_
+#define liblldb_CommandObjectCrossref_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Core/Args.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectCrossref
+//-------------------------------------------------------------------------
+
+class CommandObjectCrossref : public CommandObject
+{
+public:
+ CommandObjectCrossref (const char *name,
+ const char *help = NULL,
+ const char *syntax = NULL);
+
+ virtual
+ ~CommandObjectCrossref ();
+
+ void
+ GenerateHelpText (CommandReturnObject &result);
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual bool
+ IsCrossRefObject ();
+
+ virtual void
+ AddObject (const char *obj_name);
+
+ const char **
+ GetObjectTypes () const;
+
+private:
+ Args m_crossref_object_types;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectCrossref_h_
diff --git a/lldb/include/lldb/Interpreter/CommandObjectMultiword.h b/lldb/include/lldb/Interpreter/CommandObjectMultiword.h
new file mode 100644
index 00000000000..90f9fd0b8df
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/CommandObjectMultiword.h
@@ -0,0 +1,73 @@
+//===-- 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
+{
+public:
+ CommandObjectMultiword (const char *name,
+ const char *help = NULL,
+ const char *syntax = NULL,
+ uint32_t flags = 0);
+
+ virtual
+ ~CommandObjectMultiword ();
+
+ virtual bool
+ IsMultiwordObject () { return true; }
+
+ bool
+ LoadSubCommand (lldb::CommandObjectSP command_obj, const char *cmd_name, CommandInterpreter *interpreter);
+
+ void
+ GenerateHelpText (CommandReturnObject &result, CommandInterpreter *interpreter);
+
+ lldb::CommandObjectSP
+ GetSubcommandSP (const char *sub_cmd, StringList *matches = NULL);
+
+ CommandObject *
+ GetSubcommandObject (const char *sub_cmd, StringList *matches = NULL);
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual int
+ HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ StringList &matches);
+
+ CommandObject::CommandMap m_subcommand_dict;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectMultiword_h_
diff --git a/lldb/include/lldb/Interpreter/CommandObjectRegexCommand.h b/lldb/include/lldb/Interpreter/CommandObjectRegexCommand.h
new file mode 100644
index 00000000000..0c38f5b4fab
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/CommandObjectRegexCommand.h
@@ -0,0 +1,73 @@
+//===-- 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/Interpreter/CommandObject.h"
+#include "lldb/Core/RegularExpression.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectRegexCommand
+//-------------------------------------------------------------------------
+
+class CommandObjectRegexCommand : public CommandObject
+{
+public:
+
+ CommandObjectRegexCommand (const char *name, const char *help, const char *syntax, uint32_t max_matches);
+
+ virtual
+ ~CommandObjectRegexCommand ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual bool
+ WantsRawCommandString() { return true; }
+
+ virtual bool
+ ExecuteRawCommandString (const char *command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+
+ bool
+ AddRegexCommand (const char *re_cstr, const char *command_cstr);
+
+protected:
+ typedef struct Entry
+ {
+ RegularExpression regex;
+ std::string command;
+ };
+
+ typedef std::list<Entry> EntryCollection;
+ const uint32_t m_max_matches;
+ EntryCollection m_entries;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectRegexCommand);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectRegexCommand_h_
diff --git a/lldb/include/lldb/Interpreter/CommandReturnObject.h b/lldb/include/lldb/Interpreter/CommandReturnObject.h
new file mode 100644
index 00000000000..c95caa26002
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/CommandReturnObject.h
@@ -0,0 +1,90 @@
+//===-- 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/StreamString.h"
+
+namespace lldb_private {
+
+
+class CommandReturnObject
+{
+public:
+
+ CommandReturnObject ();
+
+ ~CommandReturnObject ();
+
+ StreamString &
+ GetOutputStream ();
+
+ StreamString &
+ GetErrorStream ();
+
+ void
+ Clear();
+
+ void
+ AppendMessage (const char *in_string, int len = -1);
+
+ void
+ AppendMessageWithFormat (const char *format, ...);
+
+ void
+ AppendRawWarning (const char *in_string, int len = -1);
+
+ void
+ AppendWarning (const char *in_string, int len = -1);
+
+ void
+ AppendWarningWithFormat (const char *format, ...);
+
+ void
+ AppendError (const char *in_string, int len = -1);
+
+ void
+ AppendRawError (const char *in_string, int len = -1);
+
+ void
+ AppendErrorWithFormat (const char *format, ...);
+
+ lldb::ReturnStatus
+ GetStatus();
+
+ void
+ SetStatus (lldb::ReturnStatus status);
+
+ bool
+ Succeeded ();
+
+ bool
+ HasResult ();
+
+ bool GetDidChangeProcessState ();
+
+ void SetDidChangeProcessState (bool b);
+
+private:
+ StreamString m_output_stream;
+ StreamString m_error_stream;
+ lldb::ReturnStatus m_status;
+ bool m_did_change_process_state;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandReturnObject_h_
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
new file mode 100644
index 00000000000..aad6e30087b
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -0,0 +1,103 @@
+//===-- 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 "PseudoTerminal.h"
+
+namespace lldb_private {
+
+class ScriptInterpreter
+{
+public:
+
+ typedef enum
+ {
+ eCharPtr,
+ eBool,
+ eShortInt,
+ eShortIntUnsigned,
+ eInt,
+ eIntUnsigned,
+ eLongInt,
+ eLongIntUnsigned,
+ eLongLong,
+ eLongLongUnsigned,
+ eFloat,
+ eDouble,
+ eChar
+ } ReturnType;
+
+
+ ScriptInterpreter (lldb::ScriptLanguage script_lang);
+
+ virtual ~ScriptInterpreter ();
+
+ virtual void
+ ExecuteOneLine (const std::string&, FILE *, FILE *) = 0;
+
+ virtual void
+ ExecuteInterpreterLoop (FILE *, FILE *) = 0;
+
+ virtual bool
+ ExecuteOneLineWithReturn (const char *in_string, ReturnType return_type, void *ret_value)
+ {
+ return true;
+ }
+
+ virtual bool
+ ExecuteMultipleLines (const char *in_string)
+ {
+ return true;
+ }
+
+ virtual bool
+ ExportFunctionDefinitionToInterpreter (StringList &function_def)
+ {
+ return false;
+ }
+
+ virtual bool
+ GenerateBreakpointCommandCallbackData (StringList &input, StringList &output)
+ {
+ return false;
+ }
+
+ virtual void
+ CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CommandReturnObject &result);
+
+ const char *
+ GetScriptInterpreterPtyName ();
+
+ int
+ GetMasterFileDescriptor ();
+
+ CommandInterpreter *
+ GetCommandInterpreter ();
+
+private:
+ lldb::ScriptLanguage m_script_lang;
+
+ // Scripting languages may need to use stdin for their interactive loops;
+ // however we don't want them to grab the real system stdin because that
+ // resource needs to be shared among the debugger UI, the inferior process and these
+ // embedded scripting loops. Therefore we need to set up a pseudoterminal and use that
+ // as stdin for the script interpreter interactive loops/prompts.
+
+ lldb_utility::PseudoTerminal m_interpreter_pty;
+ std::string m_pty_slave_name;
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_ScriptInterpreter_h_
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreterNone.h b/lldb/include/lldb/Interpreter/ScriptInterpreterNone.h
new file mode 100644
index 00000000000..919e17fa956
--- /dev/null
+++ b/lldb/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 ();
+
+ ~ScriptInterpreterNone ();
+
+ virtual void
+ ExecuteOneLine (const std::string &line, FILE *out, FILE *err);
+
+ virtual void
+ ExecuteInterpreterLoop (FILE *out, FILE *err);
+
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_ScriptInterpreterNone_h_
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h
new file mode 100644
index 00000000000..3eceb829a97
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h
@@ -0,0 +1,86 @@
+//===-- 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_
+
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Core/InputReader.h"
+
+#include <Python.h>
+
+namespace lldb_private {
+
+class ScriptInterpreterPython : public ScriptInterpreter
+{
+public:
+
+ ScriptInterpreterPython ();
+
+ ~ScriptInterpreterPython ();
+
+ void
+ ExecuteOneLine (const std::string &line, FILE *out, FILE *err);
+
+ void
+ ExecuteInterpreterLoop (FILE *out, FILE *err);
+
+ bool
+ ExecuteOneLineWithReturn (const char *in_string,
+ ScriptInterpreter::ReturnType return_type,
+ void *ret_value);
+
+ bool
+ ExecuteMultipleLines (const char *in_string);
+
+ bool
+ ExportFunctionDefinitionToInterpreter (StringList &function_def);
+
+ bool
+ GenerateBreakpointCommandCallbackData (StringList &input, StringList &output);
+
+ static size_t
+ GenerateBreakpointOptionsCommandCallback (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);
+
+ void
+ CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CommandReturnObject &result);
+
+ StringList
+ ReadCommandInputFromUser (FILE *in_file);
+
+private:
+
+ static size_t
+ InputReaderCallback (void *baton,
+ InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ PyObject *m_compiled_module;
+ struct termios m_termios;
+ bool m_termios_valid;
+};
+
+} // namespace lldb_private
+
+
+#endif // #ifndef liblldb_ScriptInterpreterPython_h_
diff --git a/lldb/include/lldb/Interpreter/StateVariable.h b/lldb/include/lldb/Interpreter/StateVariable.h
new file mode 100644
index 00000000000..34be0eedc43
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/StateVariable.h
@@ -0,0 +1,145 @@
+//===-- StateVariable.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_InterpreterStateVariable_h_
+#define liblldb_InterpreterStateVariable_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Args.h"
+
+namespace lldb_private {
+
+class StateVariable
+{
+public:
+
+ // NOTE: If you add more types to this enumeration list, you need to check for them and "do the right thing"
+ // in CommandObjectSet::Execute.
+ typedef enum
+ {
+ eTypeBoolean,
+ eTypeInteger,
+ eTypeString,
+ eTypeStringArray
+ } Type;
+
+
+ typedef bool (*Callback) (CommandInterpreter *,
+ void *,
+ CommandReturnObject &);
+
+ StateVariable (const char *name,
+ const char *value,
+ bool can_append = false,
+ const char *help_text = "",
+ Callback func_ptr = NULL);
+
+ StateVariable (const char *name,
+ bool value,
+ const char *help_text = "",
+ Callback func_ptr = NULL);
+
+ StateVariable (const char *name,
+ int value,
+ const char *help_text = "",
+ Callback func_ptr = NULL);
+
+ StateVariable (const char *name,
+ const Args *value,
+ const char *help_text = "",
+ Callback func_ptr = NULL);
+
+ virtual
+ ~StateVariable ();
+
+
+ const char *
+ GetName () const;
+
+ Type
+ GetType () const;
+
+ int
+ GetIntValue () const;
+
+ bool
+ GetBoolValue () const;
+
+ const char *
+ GetStringValue () const;
+
+ Args &
+ GetArgs ();
+
+ const Args &
+ GetArgs () const;
+
+ const char *
+ GetHelp () const;
+
+ void
+ SetHelp (const char *);
+
+ void
+ AppendVariableInformation (CommandReturnObject &result);
+
+ void
+ SetStringValue (const char *);
+
+ void
+ SetIntValue (int);
+
+ void
+ SetBoolValue (bool);
+
+ void
+ ArrayAppendValue (const char *);
+
+ void
+ ArrayClearValues ();
+
+ void
+ AppendStringValue (const char *new_string);
+
+ bool
+ VerifyValue (CommandInterpreter *interpreter,
+ void *data,
+ CommandReturnObject &result);
+
+ bool
+ HasVerifyFunction ();
+
+ static bool
+ VerifyScriptLanguage (CommandInterpreter *interpreter,
+ void *data,
+ CommandReturnObject &result);
+
+ static bool
+ BroadcastPromptChange (CommandInterpreter *interpreter,
+ void *data,
+ CommandReturnObject &result);
+
+private:
+ std::string m_name;
+ Type m_type;
+ int m_int_value;
+ Args m_string_values;
+ std::string m_help_text;
+ Callback m_verification_func_ptr;
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_InterpreterStateVariable_h_
diff --git a/lldb/include/lldb/Symbol/Block.h b/lldb/include/lldb/Symbol/Block.h
new file mode 100644
index 00000000000..1e2b23aa2f7
--- /dev/null
+++ b/lldb/include/lldb/Symbol/Block.h
@@ -0,0 +1,721 @@
+//===-- 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/Stream.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Core/VMRange.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:
+ friend class Function;
+ friend class BlockList;
+ //------------------------------------------------------------------
+ /// Enumeration values for special and invalid Block User ID
+ /// values.
+ //------------------------------------------------------------------
+ typedef enum
+ {
+ RootID = LLDB_INVALID_UID - 1, ///< The Block UID for the root block
+ InvalidID = LLDB_INVALID_UID ///< Invalid Block UID.
+ };
+
+ //------------------------------------------------------------------
+ /// 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, uint32_t depth, BlockList* block_list);
+
+ //------------------------------------------------------------------
+ /// Copy constructor.
+ ///
+ /// Makes a copy of the another Block object \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A const Block object reference to copy.
+ //------------------------------------------------------------------
+ Block (const Block& rhs);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~Block ();
+
+ //------------------------------------------------------------------
+ /// Assignment operator.
+ ///
+ /// Copies the block value from another Block object \a rhs
+ /// into \a this object.
+ ///
+ /// @param[in] rhs
+ /// A const Block object reference to copy.
+ ///
+ /// @return
+ /// A const Block object reference to \a this.
+ //------------------------------------------------------------------
+ const Block&
+ operator= (const Block& rhs);
+
+ //------------------------------------------------------------------
+ /// Add a child to this object.
+ ///
+ /// @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.
+ ///
+ /// @return
+ /// Returns \a uid if the child was successfully added to this
+ /// block, or Block::InvalidID on failure.
+ //------------------------------------------------------------------
+ lldb::user_id_t
+ AddChild (lldb::user_id_t uid);
+
+ //------------------------------------------------------------------
+ /// 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(lldb::addr_t start_offset, lldb::addr_t end_offset);
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ CalculateSymbolContext(SymbolContext* sc);
+
+ //------------------------------------------------------------------
+ /// 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 VMRange& range) const;
+
+ bool
+ ContainsBlockWithID (lldb::user_id_t block_id) 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;
+
+ void
+ DumpStopContext (Stream *s, const SymbolContext *sc);
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::DumpSymbolContext(Stream*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ DumpSymbolContext(Stream *s);
+
+ //------------------------------------------------------------------
+ /// Get the parent block's UID.
+ ///
+ /// @return
+ /// The UID of the parent block, or Block::InvalidID
+ /// if this block has no parent.
+ //------------------------------------------------------------------
+ lldb::user_id_t
+ GetParentUID () const;
+
+ //------------------------------------------------------------------
+ /// Get the sibling block's UID.
+ ///
+ /// @return
+ /// The UID of the sibling block, or Block::InvalidID
+ /// if this block has no sibling.
+ //------------------------------------------------------------------
+ lldb::user_id_t
+ GetSiblingUID () const;
+
+ //------------------------------------------------------------------
+ /// Get the first child block's UID.
+ ///
+ /// @return
+ /// The UID of the first child block, or Block::InvalidID
+ /// if this block has no first child.
+ //------------------------------------------------------------------
+ lldb::user_id_t
+ GetFirstChildUID () const;
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @return
+ /// A variable list shared pointer that contains all variables
+ /// for this block.
+ //------------------------------------------------------------------
+ lldb::VariableListSP
+ GetVariableList (bool get_child_variables, bool can_create);
+
+
+ //------------------------------------------------------------------
+ /// 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/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, VariableList *variable_list);
+
+ //------------------------------------------------------------------
+ /// Get accessor for any inlined function information.
+ ///
+ /// @return
+ /// A pointer to any inlined function information, or NULL if
+ /// this is a regular block.
+ //------------------------------------------------------------------
+ InlineFunctionInfo*
+ InlinedFunctionInfo ();
+
+ //------------------------------------------------------------------
+ /// Get const accessor for any inlined function information.
+ ///
+ /// @return
+ /// A cpmst pointer to any inlined function information, or NULL
+ /// if this is a regular block.
+ //------------------------------------------------------------------
+ const InlineFunctionInfo*
+ InlinedFunctionInfo () const;
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// 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);
+
+protected:
+ //------------------------------------------------------------------
+ /// Get accessor for the integer block depth value.
+ ///
+ /// @return
+ /// The integer depth of this block in the block hiearchy.
+ //------------------------------------------------------------------
+ uint32_t Depth () const;
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ BlockList *m_block_list; ///< The block list, one of which is this one
+ uint32_t m_depth; ///< The depth of this block where zero is the root block
+ VMRange::collection m_ranges; ///< A list of address offset ranges relative to the function's section/offset address.
+ lldb::InlineFunctionInfoSP m_inlineInfoSP; ///< Inlined function information.
+ lldb::VariableListSP m_variables; ///< The variable list for all local, static and paramter variables scoped to this block.
+ // TOOD: add a Type* list
+};
+
+//----------------------------------------------------------------------
+/// @class BlockList Block.h "lldb/Symbol/Block.h"
+/// @brief A class that contains a heirachical collection of lexical
+/// block objects where one block is the root.
+///
+/// A collection of Block objects is managed by this class. All access
+/// to the block data is made through the block_uid of each block. This
+/// facilitates partial parsing and can enable block specific data to
+/// only be parsed when the data is asked for (variables, params, types,
+/// etc).
+//----------------------------------------------------------------------
+
+class BlockList
+{
+public:
+ friend class Block;
+ typedef std::vector<Block> collection;///< Our block collection type.
+
+ //------------------------------------------------------------------
+ /// Construct with \a function and section offset based address
+ /// range.
+ ///
+ /// @param[in] function
+ /// A const Function object that owns this block list.
+ ///
+ /// @param[in] range
+ /// A section offset based address range object.
+ //------------------------------------------------------------------
+ BlockList (Function *function, const AddressRange& range);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~BlockList ();
+
+ //------------------------------------------------------------------
+ /// Add a child block to a parent block.
+ ///
+ /// Adds a new child to a parent block. The UID values for
+ /// blocks are created by the SymbolFile plug-ins and should have
+ /// values that facilitate correlating an existing Block object
+ /// with information in the debug information file. Typically
+ /// a table index, or a debug information offset is used.
+ ///
+ /// @param[in] parent_uid
+ /// The UID for a the existing parent block that will have
+ /// a new child, whose UID is \a child_uid, added to its
+ /// child list.
+ ///
+ /// @param[in] child_uid
+ /// The UID for the new child block.
+ ///
+ /// @return
+ /// Returns \a child_uid if the child was successfully added
+ /// to the parent \a parent_uid, or Block::InvalidID on
+ /// failure (if the parent doesn't exist).
+ //------------------------------------------------------------------
+ lldb::user_id_t
+ AddChild (lldb::user_id_t parent_uid, lldb::user_id_t child_uid);
+
+ //------------------------------------------------------------------
+ /// Add a child block to a parent block.
+ ///
+ /// Adds a new child to a parent block. The UID values for
+ /// blocks are created by the SymbolFile plug-ins and should have
+ /// values that facilitate correlating an existing Block object
+ /// with information in the debug information file. Typically
+ /// a table index, or a debug information offset is used.
+ ///
+ /// @param[in] block_uid
+ /// The UID for a the existing block that will get the
+ /// new range.
+ ///
+ /// @param[in] start_offset
+ /// An offset into this object's address range that
+ /// describes the start address of a range for \a block_uid.
+ ///
+ /// @param[in] end_offset
+ /// An offset into this object's address range that
+ /// describes the end address of a range for for \a block_uid.
+ ///
+ /// @return
+ /// Returns \b true if the range was successfully added to
+ /// the block whose UID is \a block_uid, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ AddRange (lldb::user_id_t block_uid, lldb::addr_t start_offset, lldb::addr_t end_offset);
+
+// const Block *
+// FindDeepestBlockForAddress (const Address &addr);
+
+ //------------------------------------------------------------------
+ /// Get accessor for the section offset based address range.
+ ///
+ /// All Block objects contained in a BlockList are relative to
+ /// the base address in this object.
+ ///
+ /// @return
+ /// Returns a reference to the section offset based address
+ /// range object.
+ //------------------------------------------------------------------
+ AddressRange &
+ GetAddressRange ();
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the section offset based address range.
+ ///
+ /// All Block objects contained in a BlockList are relative to
+ /// the base address in this object.
+ ///
+ /// @return
+ /// Returns a const reference to the section offset based
+ /// address range object.
+ //------------------------------------------------------------------
+ const AddressRange &
+ GetAddressRange () const;
+
+ //------------------------------------------------------------------
+ /// Dump the block list contents.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ ///
+ /// @param[in] block_uid
+ /// The UID of the block in the block list to dump. If this
+ /// value is Block::RootID, then the entire block list will
+ /// dumped as long as \a depth is set to a large enough value.
+ ///
+ /// @param[in] depth
+ /// Limit the number of levels deep that this function should
+ /// print as the block whose UID is \a block_uid 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::user_id_t block_uid, uint32_t depth, bool show_context) const;
+
+ //------------------------------------------------------------------
+ /// Get a block object pointer by block UID.
+ ///
+ /// @param[in] block_uid
+ /// The UID of the block to retrieve.
+ ///
+ /// @return
+ /// A pointer to the block object, or NULL if \a block_uid
+ /// doesn't exist in the block list.
+ //------------------------------------------------------------------
+ Block *
+ GetBlockByID (lldb::user_id_t block_uid);
+
+ //------------------------------------------------------------------
+ /// Get a const block object pointer by block UID.
+ ///
+ /// @param[in] block_uid
+ /// The UID of the block to retrieve.
+ ///
+ /// @return
+ /// A const pointer to the block object, or NULL if \a block_uid
+ /// doesn't exist in the block list.
+ //------------------------------------------------------------------
+ const Block *
+ GetBlockByID (lldb::user_id_t block_uid) const;
+
+ //------------------------------------------------------------------
+ /// Get a function object pointer for the block list.
+ ///
+ /// @return
+ /// A pointer to the function object.
+ //------------------------------------------------------------------
+ Function *
+ GetFunction ();
+
+ //------------------------------------------------------------------
+ /// Get a const function object pointer for the block list.
+ ///
+ /// @return
+ /// A const pointer to the function object.
+ //------------------------------------------------------------------
+ const Function *
+ GetFunction () const;
+
+ //------------------------------------------------------------------
+ /// Get the first child block UID for the block whose UID is \a
+ /// block_uid.
+ ///
+ /// @param[in] block_uid
+ /// The UID of the block we wish to access information for.
+ ///
+ /// @return
+ /// The UID of the first child block, or Block::InvalidID
+ /// if this block has no children, or if \a block_uid is not
+ /// a valid block ID for this block list.
+ //------------------------------------------------------------------
+ lldb::user_id_t
+ GetFirstChild (lldb::user_id_t block_uid) const;
+
+ //------------------------------------------------------------------
+ /// Get the parent block UID for the block whose UID is \a
+ /// block_uid.
+ ///
+ /// @param[in] block_uid
+ /// The UID of the block we wish to access information for.
+ ///
+ /// @return
+ /// The UID of the parent block, or Block::InvalidID
+ /// if this block has no parent, or if \a block_uid is not
+ /// a valid block ID for this block list.
+ //------------------------------------------------------------------
+ lldb::user_id_t
+ GetParent (lldb::user_id_t block_uid) const;
+
+ //------------------------------------------------------------------
+ /// Get the sibling block UID for the block whose UID is \a
+ /// block_uid.
+ ///
+ /// @param[in] block_uid
+ /// The UID of the block we wish to access information for.
+ ///
+ /// @return
+ /// The UID of the sibling block, or Block::InvalidID
+ /// if this block has no sibling, or if \a block_uid is not
+ /// a valid block ID for this block list.
+ //------------------------------------------------------------------
+ lldb::user_id_t
+ GetSibling (lldb::user_id_t block_uid) const;
+
+ //------------------------------------------------------------------
+ /// Get the variable list for the block whose UID is \a block_uid.
+ ///
+ /// @param[in] block_uid
+ /// The UID of the block we wish to access information for.
+ ///
+ /// @param[in] can_create
+ /// If \b true, the variable list can be parsed on demand. If
+ /// \b false, the variable list contained in this object will
+ /// be returned.
+ ///
+ /// @return
+ /// The variable list shared pointer which may contain a NULL
+ /// variable list object.
+ //------------------------------------------------------------------
+ lldb::VariableListSP
+ GetVariableList (lldb::user_id_t block_uid, bool get_child_variables, bool can_create);
+
+ //------------------------------------------------------------------
+ /// Check if the block list is empty.
+ ///
+ /// @return
+ /// Returns \b true if the block list is empty, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsEmpty () const;
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// Returns the cost of this object plus any owned objects (address
+ /// range, and contains Block objects).
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ //------------------------------------------------------------------
+ size_t
+ MemorySize () const;
+
+ //------------------------------------------------------------------
+ /// Set the variable list for the block whose UID is \a block_uid.
+ ///
+ /// @param[in] block_uid
+ /// The UID of the block we wish to set information for.
+ ///
+ /// @param[in] variable_list_sp
+ /// A shared pointer to list of variables.
+ ///
+ /// @return
+ /// Returns \b true if the variable list was successfully added
+ /// to the block, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ SetVariableList (lldb::user_id_t block_uid, lldb::VariableListSP& variable_list_sp);
+
+ //------------------------------------------------------------------
+ /// Set the inlined function info for the block whose UID is \a
+ /// block_uid.
+ ///
+ /// @param[in] block_uid
+ /// The UID of the block we wish to set information for.
+ ///
+ /// @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.
+ ///
+ /// @return
+ /// Returns \b true if the inline function info was successfully
+ /// associated with the block, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ SetInlinedFunctionInfo (lldb::user_id_t block_uid, const char *name, const char *mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ Function *m_function; ///< A pointer to the function that owns this block list.
+ AddressRange m_range; ///< The section offset based address range.
+ collection m_blocks; ///< A contiguous array of block objects.
+
+ bool
+ BlockContainsBlockWithID (const lldb::user_id_t block_id, const lldb::user_id_t find_block_id) const;
+
+private:
+
+ DISALLOW_COPY_AND_ASSIGN (BlockList);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Block_h_
diff --git a/lldb/include/lldb/Symbol/ClangASTContext.h b/lldb/include/lldb/Symbol/ClangASTContext.h
new file mode 100644
index 00000000000..56e583c1280
--- /dev/null
+++ b/lldb/include/lldb/Symbol/ClangASTContext.h
@@ -0,0 +1,417 @@
+//===-- 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
+// C++ Includes
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/ClangForward.h"
+
+
+namespace lldb_private {
+
+class Declaration;
+
+class ClangASTContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+// ClangASTContext(Module *module);
+
+ ClangASTContext(const char *target_triple);
+
+// ClangASTContext(const ConstString &target_triple);
+
+ ~ClangASTContext();
+
+ clang::ASTContext *
+ getASTContext();
+
+ clang::Builtin::Context *
+ getBuiltinContext();
+
+ clang::IdentifierTable *
+ getIdentifierTable();
+
+ clang::LangOptions *
+ getLanguageOptions();
+
+ clang::SelectorTable *
+ getSelectorTable();
+
+ clang::SourceManager *
+ getSourceManager();
+
+ clang::Diagnostic *
+ getDiagnostic();
+
+ clang::TargetOptions *
+ getTargetOptions();
+
+ clang::TargetInfo *
+ getTargetInfo();
+
+ void
+ Clear();
+
+ const char *
+ GetTargetTriple ();
+
+ void
+ SetTargetTriple (const char *target_triple);
+
+ //------------------------------------------------------------------
+ // Basic Types
+ //------------------------------------------------------------------
+
+ void *
+ GetBuiltinTypeForEncodingAndBitSize (lldb::Encoding encoding,
+ uint32_t bit_size);
+
+ static void *
+ GetBuiltinTypeForEncodingAndBitSize (clang::ASTContext *ast_context,
+ lldb::Encoding encoding,
+ uint32_t bit_size);
+
+ void *
+ GetBuiltinTypeForDWARFEncodingAndBitSize (
+ const char *type_name,
+ uint32_t dw_ate,
+ uint32_t bit_size);
+
+ void *
+ GetVoidBuiltInType();
+
+ void *
+ GetCStringType(bool is_const);
+
+ void *
+ GetVoidPtrType(bool is_const);
+
+ static void *
+ GetVoidPtrType(clang::ASTContext *ast_context, bool is_const);
+
+ static void *
+ CopyType(clang::ASTContext *dest_context,
+ clang::ASTContext *source_context,
+ void * clang_type);
+
+ //------------------------------------------------------------------
+ // CVR modifiers
+ //------------------------------------------------------------------
+
+ static void *
+ AddConstModifier (void * clang_type);
+
+ static void *
+ AddRestrictModifier (void * clang_type);
+
+ static void *
+ AddVolatileModifier (void * clang_type);
+
+ //------------------------------------------------------------------
+ // Structure, Unions, Classes
+ //------------------------------------------------------------------
+
+ void *
+ CreateRecordType (
+ const char *name,
+ int kind,
+ clang::DeclContext *decl_ctx);
+
+ bool
+ AddFieldToRecordType (
+ void * record_qual_type,
+ const char *name,
+ void * field_type,
+ int access,
+ uint32_t bitfield_bit_size);
+
+ bool
+ FieldIsBitfield (
+ clang::FieldDecl* field,
+ uint32_t& bitfield_bit_size);
+
+ static bool
+ FieldIsBitfield (
+ clang::ASTContext *ast_context,
+ clang::FieldDecl* field,
+ uint32_t& bitfield_bit_size);
+
+ static bool
+ RecordHasFields (const clang::RecordDecl *record_decl);
+
+ void
+ SetDefaultAccessForRecordFields (
+ void * clang_qual_type,
+ int default_accessibility,
+ int *assigned_accessibilities,
+ size_t num_assigned_accessibilities);
+
+ //------------------------------------------------------------------
+ // Aggregate Types
+ //------------------------------------------------------------------
+ static bool
+ IsAggregateType (void * clang_type);
+
+ static uint32_t
+ GetNumChildren (
+ void * clang_type,
+ bool omit_empty_base_classes);
+
+ void *
+ GetChildClangTypeAtIndex (
+ const char *parent_name,
+ void * parent_clang_type,
+ uint32_t idx,
+ bool transparent_pointers,
+ bool omit_empty_base_classes,
+ 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);
+
+ static void *
+ GetChildClangTypeAtIndex (
+ clang::ASTContext *ast_context,
+ const char *parent_name,
+ void * parent_clang_type,
+ uint32_t idx,
+ bool transparent_pointers,
+ bool omit_empty_base_classes,
+ 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);
+
+ // Lookup a child given a name. This function will match base class names
+ // and member member names in "clang_type" only, not descendants.
+ static uint32_t
+ GetIndexOfChildWithName (clang::ASTContext *ast_context,
+ void *clang_type,
+ const char *name,
+ bool omit_empty_base_classes);
+
+ // 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.
+ static size_t
+ GetIndexOfChildMemberWithName (clang::ASTContext *ast_context,
+ void *clang_type,
+ const char *name,
+ bool omit_empty_base_classes,
+ std::vector<uint32_t>& child_indexes);
+
+ //------------------------------------------------------------------
+ // clang::TagType
+ //------------------------------------------------------------------
+
+ bool
+ SetTagTypeKind (
+ void * tag_qual_type,
+ int kind);
+
+ //------------------------------------------------------------------
+ // C++ Base Classes
+ //------------------------------------------------------------------
+
+ clang::CXXBaseSpecifier *
+ CreateBaseClassSpecifier (
+ void * base_class_type,
+ int access,
+ bool is_virtual,
+ bool base_of_class);
+
+ bool
+ SetBaseClassesForClassType (
+ void * class_clang_type,
+ clang::CXXBaseSpecifier const * const *base_classes,
+ unsigned num_base_classes);
+
+ //------------------------------------------------------------------
+ // DeclContext Functions
+ //------------------------------------------------------------------
+
+ static clang::DeclContext *
+ GetDeclContextForType (void * qual_type);
+
+ //------------------------------------------------------------------
+ // Namespace Declarations
+ //------------------------------------------------------------------
+
+ clang::NamespaceDecl *
+ GetUniqueNamespaceDeclaration (
+ const char *name,
+ const Declaration &decl,
+ clang::DeclContext *decl_ctx);
+
+ //------------------------------------------------------------------
+ // Function Types
+ //------------------------------------------------------------------
+
+ clang::FunctionDecl *
+ CreateFunctionDeclaration (
+ const char *name,
+ void * function_Type,
+ int storage,
+ bool is_inline);
+
+ void *
+ CreateFunctionType (
+ void * result_type,
+ void **args,
+ unsigned num_args,
+ bool isVariadic,
+ unsigned TypeQuals);
+
+ clang::ParmVarDecl *
+ CreateParmeterDeclaration (
+ const char *name,
+ void * return_type,
+ int storage);
+
+ void
+ SetFunctionParameters (
+ clang::FunctionDecl *function_decl,
+ clang::ParmVarDecl **params,
+ unsigned num_params);
+
+ //------------------------------------------------------------------
+ // Array Types
+ //------------------------------------------------------------------
+
+ void *
+ CreateArrayType (
+ void * element_type,
+ size_t element_count,
+ uint32_t bit_stride);
+
+ //------------------------------------------------------------------
+ // Tag Declarations
+ //------------------------------------------------------------------
+ bool
+ StartTagDeclarationDefinition (void * qual_type);
+
+ bool
+ CompleteTagDeclarationDefinition (void * qual_type);
+
+ //------------------------------------------------------------------
+ // Enumeration Types
+ //------------------------------------------------------------------
+ void *
+ CreateEnumerationType (const Declaration &decl, const char *name);
+
+ bool
+ AddEnumerationValueToEnumerationType (
+ void * enum_qual_type,
+ void * enumerator_qual_type,
+ const Declaration &decl,
+ const char *name,
+ int64_t enum_value,
+ uint32_t enum_value_bit_size);
+
+ //------------------------------------------------------------------
+ // Pointers & References
+ //------------------------------------------------------------------
+ void *
+ CreatePointerType (void * clang_type);
+
+ void *
+ CreateLValueReferenceType (void * clang_type);
+
+ void *
+ CreateRValueReferenceType (void * clang_type);
+
+ size_t
+ GetPointerBitSize ();
+
+ static size_t
+ GetTypeBitSize (clang::ASTContext *ast_context, void * clang_type);
+
+ static size_t
+ GetTypeBitAlign (clang::ASTContext *ast_context, void * clang_type);
+
+ static bool
+ IsIntegerType (void * clang_type, bool &is_signed);
+
+ static bool
+ IsPointerType (void * clang_type, void **target_type = NULL);
+
+ static bool
+ IsPointerOrReferenceType (void * clang_type, void **target_type = NULL);
+
+ static bool
+ IsCStringType (void * clang_type, uint32_t &length);
+
+ static bool
+ IsArrayType (void * clang_type, void **member_type = NULL, uint64_t *size = NULL);
+
+ //------------------------------------------------------------------
+ // Typedefs
+ //------------------------------------------------------------------
+ void *
+ CreateTypedefType (
+ const char *name,
+ void * clang_type,
+ clang::DeclContext *decl_ctx);
+
+ //------------------------------------------------------------------
+ // Type names
+ //------------------------------------------------------------------
+ static std::string
+ GetTypeName(void *clang_type);
+
+ static bool
+ IsFloatingPointType (void * clang_type, uint32_t &count, bool &is_complex);
+
+ //static bool
+ //ConvertFloatValueToString (clang::ASTContext *ast_context, void * clang_type, const uint8_t* bytes, size_t byte_size, int apint_byte_order, std::string &float_str);
+
+ static size_t
+ ConvertStringToFloatValue (clang::ASTContext *ast_context, void * clang_type, const char *s, uint8_t *dst, size_t dst_size);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from ClangASTContext can see and modify these
+ //------------------------------------------------------------------
+ std::string m_target_triple;
+ std::auto_ptr<clang::ASTContext> m_ast_context_ap;
+ std::auto_ptr<clang::LangOptions> m_language_options_ap;
+ std::auto_ptr<clang::SourceManager> m_source_manager_ap;
+ std::auto_ptr<clang::Diagnostic> m_diagnostic_ap;
+ std::auto_ptr<clang::TargetOptions> m_target_options_ap;
+ std::auto_ptr<clang::TargetInfo> m_target_info_ap;
+ std::auto_ptr<clang::IdentifierTable> m_identifier_table_ap;
+ std::auto_ptr<clang::SelectorTable> m_selector_table_ap;
+ std::auto_ptr<clang::Builtin::Context> m_builtins_ap;
+
+private:
+ //------------------------------------------------------------------
+ // For ClangASTContext only
+ //------------------------------------------------------------------
+ ClangASTContext(const ClangASTContext&);
+ const ClangASTContext& operator=(const ClangASTContext&);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangASTContext_h_
diff --git a/lldb/include/lldb/Symbol/CompileUnit.h b/lldb/include/lldb/Symbol/CompileUnit.h
new file mode 100644
index 00000000000..15c3714a731
--- /dev/null
+++ b/lldb/include/lldb/Symbol/CompileUnit.h
@@ -0,0 +1,395 @@
+//===-- 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/Symbol/Function.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/Language.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 ModuleChild,
+ public FileSpec,
+ public UserID,
+ public Language,
+ 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 Language::Type
+ //------------------------------------------------------------------
+ CompileUnit(Module *module, void *user_data, const char *pathname, lldb::user_id_t uid, Language::Type 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 Language::Type
+ //------------------------------------------------------------------
+ CompileUnit(Module *module, void *user_data, const FileSpec &file_spec, lldb::user_id_t uid, Language::Type language);
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~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);
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::DumpSymbolContext(Stream*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ DumpSymbolContext(Stream *s);
+
+ //------------------------------------------------------------------
+ /// 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[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,
+ 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.
+ 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::auto_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 = (1 << 0), ///< Have we already parsed all our functions
+ flagsParsedVariables = (1 << 1), ///< Have we already parsed globals and statics?
+ flagsParsedSupportFiles = (1 << 2), ///< Have we already parsed the support files for this compile unit?
+ flagsParsedLineTable = (1 << 3), ///< Have we parsed the line table already?
+ };
+
+ DISALLOW_COPY_AND_ASSIGN (CompileUnit);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CompUnit_h_
diff --git a/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h b/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h
new file mode 100644
index 00000000000..08dc42e2d1d
--- /dev/null
+++ b/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h
@@ -0,0 +1,312 @@
+//===-- 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_
+
+// C Includes
+// C++ Includes
+#include <map>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/VMRange.h"
+#include "lldb/Core/dwarf.h"
+
+namespace lldb_private {
+//----------------------------------------------------------------------
+// DWARFCallFrameInfo
+//
+// State that describes all register locations for a given address
+// range.
+//----------------------------------------------------------------------
+
+class DWARFCallFrameInfo
+{
+public:
+ enum
+ {
+ CFI_AUG_MAX_SIZE = 8,
+ CFI_HEADER_SIZE = 8
+ };
+
+ class Row;
+
+ class RegisterLocation
+ {
+ public:
+
+ typedef enum Type
+ {
+ 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...
+ isUndefined, // reg is not available
+ isSame, // 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();
+
+ bool
+ operator == (const RegisterLocation& rhs) const;
+
+ void
+ Dump(Stream *s, const DWARFCallFrameInfo &cfi, Thread *thread, const Row *row, uint32_t reg_num) const;
+
+ void
+ SetUnspecified();
+
+ void
+ SetUndefined();
+
+ void
+ SetSame() ;
+
+ void
+ SetAtCFAPlusOffset (int64_t offset);
+
+ void
+ SetIsCFAPlusOffset (int64_t offset);
+
+ void
+ SetInRegister (uint32_t reg_num);
+
+ void
+ SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len);
+
+ void
+ SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len);
+
+ protected:
+ Type 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;
+ uint32_t length;
+ } expr;
+ } m_location;
+ };
+
+ class Row
+ {
+ public:
+
+ Row ();
+
+ ~Row ();
+
+ void
+ Clear();
+
+ void
+ Dump(Stream* s, const DWARFCallFrameInfo &cfi, Thread *thread, lldb::addr_t base_addr) 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 slide)
+ {
+ m_offset += slide;
+ }
+
+ uint32_t
+ GetCFARegister () const
+ {
+ return m_cfa_reg_num;
+ }
+
+ void
+ SetCFARegister (uint32_t reg_num)
+ {
+ m_cfa_reg_num = reg_num;
+ }
+
+ int32_t
+ GetCFAOffset () const
+ {
+ return m_cfa_offset;
+ }
+
+ void
+ SetCFAOffset (int32_t offset)
+ {
+ m_cfa_offset = offset;
+ }
+
+ protected:
+ typedef std::map<uint32_t, RegisterLocation> collection;
+ lldb::addr_t m_offset; // The an offset into the DBAddressRange that owns 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;
+ };
+
+ //------------------------------------------------------------------
+ // Common Information Entry (CIE)
+ //------------------------------------------------------------------
+protected:
+
+ struct CIE
+ {
+ typedef lldb::SharedPtr<CIE>::Type shared_ptr;
+ dw_offset_t cie_offset;
+ uint8_t version;
+ char augmentation[CFI_AUG_MAX_SIZE]; // This is typically empty or very short. If we ever run into the limit, make this a NSData pointer
+ 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;
+
+ CIE(dw_offset_t offset);
+ ~CIE();
+
+ void
+ Dump(Stream *s, Thread* threadState, const ArchSpec *arch, uint32_t reg_kind) const;
+ };
+
+ //------------------------------------------------------------------
+ // Frame Description Entry (FDE)
+ //------------------------------------------------------------------
+public:
+
+ class FDE
+ {
+ public:
+ typedef lldb::SharedPtr<FDE>::Type shared_ptr;
+
+ FDE (uint32_t offset, const AddressRange &range);
+ ~FDE();
+
+ const AddressRange &
+ GetAddressRange() const;
+
+ void
+ AppendRow (const Row &row);
+
+ bool
+ IsValidRowIndex (uint32_t idx) const;
+
+ void
+ Dump (Stream *s, const DWARFCallFrameInfo &cfi, Thread* thread) const;
+
+ const Row&
+ GetRowAtIndex (uint32_t idx);
+
+ protected:
+ typedef std::vector<Row> collection;
+ uint32_t m_fde_offset;
+ AddressRange m_range;
+ collection m_row_list;
+ private:
+ DISALLOW_COPY_AND_ASSIGN (FDE);
+ };
+
+ DWARFCallFrameInfo(ObjectFile *objfile, lldb_private::Section *section, uint32_t reg_kind);
+
+ ~DWARFCallFrameInfo();
+
+ bool
+ IsEHFrame() const;
+
+ const ArchSpec *
+ GetArchitecture() const;
+
+ uint32_t
+ GetRegisterKind () const;
+
+ void
+ SetRegisterKind (uint32_t reg_kind);
+
+ void
+ Index ();
+
+// bool UnwindRegister (const uint32_t reg_num, const Thread* currState, const Row* row, Thread* unwindState);
+// uint32_t UnwindThreadState(const Thread* curr_state, bool is_first_frame, Thread* unwound_state);
+ const FDE *
+ FindFDE(const Address &addr);
+
+ void
+ Dump(Stream *s, Thread *thread) const;
+
+ void
+ ParseAll();
+protected:
+
+ enum
+ {
+ eFlagParsedIndex = (1 << 0)
+ };
+
+ typedef std::map<off_t, CIE::shared_ptr> cie_map_t;
+ struct FDEInfo
+ {
+ off_t fde_offset;
+ FDE::shared_ptr fde_sp;
+ FDEInfo (off_t offset);
+ FDEInfo ();
+
+ };
+ typedef std::map<VMRange, FDEInfo> fde_map_t;
+
+ ObjectFile * m_objfile;
+ lldb_private::Section * m_section;
+ uint32_t m_reg_kind;
+ Flags m_flags;
+ DataExtractor m_cfi_data;
+ cie_map_t m_cie_map;
+ fde_map_t m_fde_map;
+
+ const CIE*
+ GetCIE (uint32_t offset);
+
+ void
+ ParseInstructions(const CIE *cie, FDE *fde, uint32_t instr_offset, uint32_t instr_length);
+
+ CIE::shared_ptr
+ ParseCIE (const uint32_t cie_offset);
+
+ FDE::shared_ptr
+ ParseFDE (const uint32_t fde_offset);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_DWARFCallFrameInfo_h_
diff --git a/lldb/include/lldb/Symbol/Declaration.h b/lldb/include/lldb/Symbol/Declaration.h
new file mode 100644
index 00000000000..ba0c68d43e6
--- /dev/null
+++ b/lldb/include/lldb/Symbol/Declaration.h
@@ -0,0 +1,204 @@
+//===-- 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/Core/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 ();
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// Construct with a reference to another Declaration object.
+ //------------------------------------------------------------------
+ Declaration (const Declaration& rhs);
+
+ //------------------------------------------------------------------
+ /// Construct with a pointer to another Declaration object.
+ //------------------------------------------------------------------
+ Declaration (const Declaration* rhs_ptr);
+
+ //------------------------------------------------------------------
+ /// Clear the object's state.
+ ///
+ /// Sets the file specification to be empty, and the line and column
+ /// to zero.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// 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) const;
+
+ void
+ DumpStopContext (Stream *s) 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;
+
+ //------------------------------------------------------------------
+ /// Get accessor for file specification.
+ ///
+ /// @return
+ /// A reference to the file specification object.
+ //------------------------------------------------------------------
+ FileSpec&
+ GetFile ();
+
+ //------------------------------------------------------------------
+ /// Get const accessor for file specification.
+ ///
+ /// @return
+ /// A const reference to the file specification object.
+ //------------------------------------------------------------------
+ const FileSpec&
+ GetFile () const;
+
+ //------------------------------------------------------------------
+ /// 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;
+
+
+ bool
+ IsValid() 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 ()
+ //------------------------------------------------------------------
+ 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);
+
+ //------------------------------------------------------------------
+ /// Set accessor for the declaration file specification.
+ ///
+ /// @param[in] file_spec
+ /// The new declaration file specifciation.
+ //------------------------------------------------------------------
+ void
+ SetFile (const FileSpec& 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);
+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.
+ uint32_t m_column; ///< Non-zero values indicates a valid column number,
+ ///< zero indicates no column information is available.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Declaration_h_
diff --git a/lldb/include/lldb/Symbol/Function.h b/lldb/include/lldb/Symbol/Function.h
new file mode 100644
index 00000000000..74029da1e06
--- /dev/null
+++ b/lldb/include/lldb/Symbol/Function.h
@@ -0,0 +1,587 @@
+//===-- 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/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) 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) const;
+
+ void
+ DumpStopContext (Stream *s) 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);
+
+ const AddressRange &
+ GetAddressRange();
+
+ //------------------------------------------------------------------
+ /// Get accessor for the block list.
+ ///
+ /// @return
+ /// The block list object that describes all lexical blocks
+ /// in the function.
+ ///
+ /// @see BlockList
+ //------------------------------------------------------------------
+ BlockList&
+ GetBlocks (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;
+
+ //------------------------------------------------------------------
+ /// 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 Mangled &
+ GetMangled() const
+ {
+ return m_mangled;
+ }
+
+ //------------------------------------------------------------------
+ /// 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;
+
+ Type
+ GetReturnType ();
+
+ // The Number of arguments, or -1 for an unprototyped function.
+ int
+ GetArgumentCount ();
+
+ const Type
+ GetArgumentTypeAtIndex (size_t idx);
+
+ const char *
+ GetArgumentNameAtIndex (size_t idx);
+
+ bool
+ IsVariadic ();
+
+ 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.
+ BlockList m_blocks; ///< All lexical blocks contained in this function.
+ 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/lldb/include/lldb/Symbol/LineEntry.h b/lldb/include/lldb/Symbol/LineEntry.h
new file mode 100644
index 00000000000..e0e6d2941d1
--- /dev/null
+++ b/lldb/include/lldb/Symbol/LineEntry.h
@@ -0,0 +1,170 @@
+//===-- 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/Core/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
+ (
+ Section *section,
+ 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, Process *process, bool show_file, Address::DumpStyle style, Address::DumpStyle fallback_style, bool show_range) const;
+
+ bool
+ GetDescription (Stream *s, lldb::DescriptionLevel level, CompileUnit* cu, Process *process) 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) 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/lldb/include/lldb/Symbol/LineTable.h b/lldb/include/lldb/Symbol/LineTable.h
new file mode 100644
index 00000000000..2329eea3720
--- /dev/null
+++ b/lldb/include/lldb/Symbol/LineTable.h
@@ -0,0 +1,333 @@
+//===-- 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"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @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 guarantee the addresses are in increasing order
+ void
+ AppendLineEntry (lldb::SectionSP& section_sp,
+ lldb::addr_t section_offset,
+ 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);
+
+ // Called when you can't guarantee the addresses are in increasing order
+ void
+ InsertLineEntry (lldb::SectionSP& section_sp,
+ lldb::addr_t section_offset,
+ 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);
+
+ //------------------------------------------------------------------
+ /// 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, Process *process, Address::DumpStyle style, Address::DumpStyle fallback_style, bool show_line_ranges);
+
+ void
+ GetDescription (Stream *s, Process *process, 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);
+
+ //------------------------------------------------------------------
+ /// 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;
+
+protected:
+
+ struct Entry
+ {
+ enum { kInvalidSectIdx = 255 };
+
+ Entry () :
+ sect_idx (kInvalidSectIdx),
+ sect_offset (0),
+ 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 ( uint8_t _sect_idx,
+ lldb::addr_t _sect_offset,
+ 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) :
+ sect_idx (_sect_idx),
+ sect_offset (_sect_offset),
+ 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)
+ {
+ // We have reserved 24 bits for the section offset which should
+ // be enough, but if it isn't then we need to make m_section_offset
+ // bigger
+ assert((_sect_offset & 0xffffffffff000000ull) == 0);
+ }
+
+ int
+ bsearch_compare (const void *key, const void *arrmem);
+
+ void
+ Clear ()
+ {
+ sect_idx = kInvalidSectIdx;
+ sect_offset = 0;
+ 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.sect_offset, rhs.sect_offset);
+ 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& a, const LineTable::Entry& a) const;
+ protected:
+ LineTable *m_line_table;
+ };
+
+ static bool EntryAddressLessThan (const Entry& lhs, const Entry& rhs)
+ {
+ if (lhs.sect_idx == rhs.sect_idx)
+ return lhs.sect_offset < rhs.sect_offset;
+ return lhs.sect_idx < rhs.sect_idx;
+ }
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ uint32_t sect_idx:8, ///< The section index for this line entry.
+ sect_offset:24; ///< The offset into the section 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 line entries.
+ 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.
+ SectionList m_section_list; ///< The list of sections that at least one of the line entries exists in.
+ entry_collection m_entries; ///< The collection of line entries in this line table.
+
+ bool
+ ConvertEntryAtIndexToLineEntry (uint32_t idx, LineEntry &line_entry);
+
+ lldb_private::Section *
+ GetSectionForEntryIndex (uint32_t idx);
+private:
+ DISALLOW_COPY_AND_ASSIGN (LineTable);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_LineTable_h_
diff --git a/lldb/include/lldb/Symbol/ObjectContainer.h b/lldb/include/lldb/Symbol/ObjectContainer.h
new file mode 100644
index 00000000000..f5c6d0780f8
--- /dev/null
+++ b/lldb/include/lldb/Symbol/ObjectContainer.h
@@ -0,0 +1,232 @@
+//===-- 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/Core/FileSpec.h"
+#include "lldb/Core/ModuleChild.h"
+#include "lldb/Core/PluginInterface.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 (Module* module,
+ const FileSpec *file,
+ lldb::addr_t offset,
+ lldb::addr_t length,
+ lldb::DataBufferSP& headerDataSP) :
+ ModuleChild (module),
+ m_file (), // This file can be different than the module's file spec
+ m_offset (offset),
+ m_length (length),
+ m_data (headerDataSP, lldb::eByteOrderHost, 4)
+ {
+ if (file)
+ m_file = *file;
+ }
+
+ //------------------------------------------------------------------
+ /// 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 ObjectFile *
+ 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/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h
new file mode 100644
index 00000000000..f9e5c2da111
--- /dev/null
+++ b/lldb/include/lldb/Symbol/ObjectFile.h
@@ -0,0 +1,309 @@
+//===-- 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/Core/ModuleChild.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Symbol/Symtab.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).
+///
+/// It is possible to determine how many architectures an object file
+/// contains by using the ObjectFile::GetNumArchitectures() const
+/// accessor function. The individual architectures can be extracted
+/// using the
+/// ObjectFile::GetArchitectureAtIndex (uint32_t, ArchSpec&) const
+/// function. The object file can also be asked to select one of these
+/// architectures using the
+/// ObjectFile::SetArchitecture (const ArchSpec&) function.
+///
+/// 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 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.
+ //------------------------------------------------------------------
+ ObjectFile (Module* module, const FileSpec *file_spec_ptr, lldb::addr_t offset, lldb::addr_t length, lldb::DataBufferSP& headerDataSP) :
+ ModuleChild (module),
+ m_file (), // This file could be different from the original module's file
+ m_offset (offset),
+ m_length (length),
+ m_data (headerDataSP, lldb::eByteOrderHost, 4)
+ {
+ if (file_spec_ptr)
+ m_file = *file_spec_ptr;
+ }
+
+ //------------------------------------------------------------------
+ /// 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 ObjectFile*
+ FindPlugin (Module* module,
+ const FileSpec* file_spec,
+ lldb::addr_t file_offset,
+ lldb::addr_t file_size);
+
+ //------------------------------------------------------------------
+ /// 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 size_t
+ GetAddressByteSize () const = 0;
+
+ //------------------------------------------------------------------
+ /// 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;
+
+ //------------------------------------------------------------------
+ /// 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 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
+ GetTargetTriple(ConstString &target_triple) = 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 () = 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;
+
+ //------------------------------------------------------------------
+ /// 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 (UUID* uuid) = 0;
+
+ //------------------------------------------------------------------
+ /// Gets wether 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;
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ FileSpec m_file;
+ lldb::addr_t m_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.
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (ObjectFile);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ObjectFile_h_
+
diff --git a/lldb/include/lldb/Symbol/Symbol.h b/lldb/include/lldb/Symbol/Symbol.h
new file mode 100644
index 00000000000..ec5596fe0b0
--- /dev/null
+++ b/lldb/include/lldb/Symbol/Symbol.h
@@ -0,0 +1,181 @@
+//===-- 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"
+
+namespace lldb_private {
+
+class Symbol :
+ public UserID // Used to uniquely identify this symbol in its symbol table
+{
+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 (lldb::user_id_t symID,
+ const char *name,
+ bool name_is_mangled,
+ lldb::SymbolType type,
+ bool external,
+ bool is_debug,
+ bool is_trampoline,
+ bool is_artificial,
+ const Section* section,
+ lldb::addr_t value,
+ uint32_t size,
+ uint32_t flags);
+
+ Symbol (lldb::user_id_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,
+ uint32_t flags);
+
+ Symbol (const Symbol& rhs);
+
+ const Symbol&
+ operator= (const Symbol& rhs);
+
+ bool
+ Compare (const ConstString& name, lldb::SymbolType type) const;
+
+ void
+ Dump (Stream *s, Process *process, uint32_t index) const;
+
+ AddressRange *
+ GetAddressRangePtr ();
+
+ const AddressRange *
+ GetAddressRangePtr () const;
+
+ AddressRange &
+ GetAddressRangeRef();
+
+ const AddressRange &
+ GetAddressRangeRef() const;
+
+ Mangled&
+ GetMangled ();
+
+ const Mangled&
+ GetMangled () const;
+
+ bool
+ GetSizeIsSibling () const;
+
+ bool
+ GetSizeIsSynthesized() const;
+
+ uint32_t
+ GetSiblingIndex () const;
+
+ uint32_t
+ GetByteSize () const;
+
+ lldb::SymbolType
+ GetType () const;
+
+ void
+ SetType (lldb::SymbolType type);
+
+ const char *
+ GetTypeAsString () const;
+
+ uint32_t
+ GetFlags () const;
+
+ void
+ SetFlags (uint32_t flags);
+
+ Function *
+ GetFunction ();
+
+ Address &
+ GetValue ();
+
+ const Address &
+ GetValue () const;
+
+ bool
+ IsSynthetic () const;
+
+ void
+ SetIsSynthetic (bool b);
+
+ void
+ SetSizeIsSynthesized(bool b);
+
+ bool
+ IsDebug () const;
+
+ void
+ SetDebug (bool b);
+
+ bool
+ IsExternal () const;
+
+ void
+ SetExternal (bool b);
+
+ bool
+ IsTrampoline () const;
+
+ void
+ SetByteSize (uint32_t size);
+
+ void
+ SetSizeIsSibling (bool b);
+
+ void
+ SetValue (Address &value);
+
+ void
+ SetValue (const AddressRange &range);
+
+ void
+ SetValue (lldb::addr_t 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 ();
+
+protected:
+
+ Mangled m_mangled; // uniqued symbol name/mangled name pair
+ lldb::SymbolType m_type; // symbol type
+ 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_searched_for_function:1;// non-zero if we have looked for the function associated with this symbol already.
+ 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
+ Function * m_function;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Symbol_h_
diff --git a/lldb/include/lldb/Symbol/SymbolContext.h b/lldb/include/lldb/Symbol/SymbolContext.h
new file mode 100644
index 00000000000..c0aff6ea4a7
--- /dev/null
+++ b/lldb/include/lldb/Symbol/SymbolContext.h
@@ -0,0 +1,328 @@
+//===-- 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/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);
+
+ //------------------------------------------------------------------
+ /// 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 ();
+
+ //------------------------------------------------------------------
+ /// 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, Process *process) 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 ouput. 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.
+ //------------------------------------------------------------------
+ void
+ DumpStopContext (Stream *s,
+ ExecutionContextScope *exe_scope,
+ const Address &so_addr,
+ bool show_module = true) 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
+ /// - function address range if function is not NULL
+ /// - symbol address range if symbol is not NULL
+ ///
+ /// @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, AddressRange &range) const;
+
+ //------------------------------------------------------------------
+ /// Find a function matching the given name, working out from this
+ /// symbol context.
+ ///
+ /// @return
+ /// A shared pointer to the function found.
+ //------------------------------------------------------------------
+ Function *
+ FindFunctionByName (const char *name) const;
+
+ //------------------------------------------------------------------
+ /// Find a variable matching the given name, working out from this
+ /// symbol context.
+ ///
+ /// @return
+ /// A shared pointer to the variable found.
+ //------------------------------------------------------------------
+ lldb::VariableSP
+ FindVariableByName (const char *name) const;
+
+ //------------------------------------------------------------------
+ /// Find a type matching the given name, working out from this
+ /// symbol context.
+ ///
+ /// @return
+ /// A shared pointer to the variable found.
+ //------------------------------------------------------------------
+ lldb::TypeSP
+ FindTypeByName (const char *name) 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 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);
+
+ //------------------------------------------------------------------
+ /// 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, Process *process) 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(uint32_t idx, SymbolContext& sc) const;
+
+ bool
+ RemoveContextAtIndex (uint32_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;
+
+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);
+
+} // namespace lldb_private
+
+#endif // liblldb_SymbolContext_h_
diff --git a/lldb/include/lldb/Symbol/SymbolContextScope.h b/lldb/include/lldb/Symbol/SymbolContextScope.h
new file mode 100644
index 00000000000..9b9b9d698ae
--- /dev/null
+++ b/lldb/include/lldb/Symbol/SymbolContextScope.h
@@ -0,0 +1,79 @@
+//===-- 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 can reconstruct its symbol
+/// context.
+///
+/// Many objects that have pointers back to parent objects that own them
+/// that all inherit from this pure virtual class can reconstruct their
+/// symbol context without having to keep a complete SymbolContextScope
+/// object in the object state. Examples of these objects include:
+/// Module, CompileUnit, Function, and Block.
+///
+/// Other objects can contain a valid pointer to an instance of this
+/// class so they can reconstruct the symbol context in which they are
+/// scoped. Example objects include: Variable and Type. Such objects
+/// can be scoped at a variety of levels:
+/// @li module level for a built built in types.
+/// @li file level for compile unit types and variables.
+/// @li function or block level for types and variables defined in
+/// a function body.
+///
+/// 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:
+ //------------------------------------------------------------------
+ /// 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;
+
+ //------------------------------------------------------------------
+ /// 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/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
new file mode 100644
index 00000000000..4af88c31b06
--- /dev/null
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -0,0 +1,95 @@
+//===-- 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/Type.h"
+
+namespace lldb_private {
+
+class SymbolFile :
+ public PluginInterface
+{
+public:
+ enum Abilities
+ {
+ Labels = (1 << 0),
+ AddressAcceleratorTable = (1 << 1),
+ FunctionAcceleratorTable = (1 << 2),
+ TypeAcceleratorTable = (1 << 3),
+ MacroInformation = (1 << 4),
+ CallFrameInformation = (1 << 5),
+ CompileUnits = (1 << 6),
+ LineTables = (1 << 7),
+ LineColumns = (1 << 8),
+ Functions = (1 << 9),
+ Blocks = (1 << 10),
+ GlobalVariables = (1 << 11),
+ LocalVariables = (1 << 12),
+ VariableTypes = (1 << 13)
+ };
+
+ static SymbolFile *
+ FindPlugin (ObjectFile* obj_file);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolFile(ObjectFile* obj_file) :
+ m_obj_file(obj_file)
+ {
+ }
+
+ virtual
+ ~SymbolFile()
+ {
+ }
+
+ virtual uint32_t GetAbilities () = 0;
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ // Approach 1 - iterator
+ virtual uint32_t GetNumCompileUnits() = 0;
+ virtual lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) = 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 clang::DeclContext* GetClangDeclContextForTypeUID (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, 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, bool append, SymbolContextList& sc_list) = 0;
+ virtual uint32_t FindFunctions (const RegularExpression& regex, bool append, SymbolContextList& sc_list) = 0;
+// virtual uint32_t FindTypes (const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types) = 0;
+// virtual uint32_t FindTypes (const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types) = 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.
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (SymbolFile);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_SymbolFile_h_
diff --git a/lldb/include/lldb/Symbol/SymbolVendor.h b/lldb/include/lldb/Symbol/SymbolVendor.h
new file mode 100644
index 00000000000..a5bdb3b30b1
--- /dev/null
+++ b/lldb/include/lldb/Symbol/SymbolVendor.h
@@ -0,0 +1,193 @@
+//===-- 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/Host/Mutex.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 bool
+ RegisterPlugin (const char *name,
+ const char *description,
+ SymbolVendorCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (SymbolVendorCreateInstance create_callback);
+
+
+ static SymbolVendor*
+ FindPlugin (Module* module);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolVendor(Module *module);
+
+ virtual
+ ~SymbolVendor();
+
+ void
+ AddSymbolFileRepresendation(ObjectFile *obj_file);
+
+ virtual void
+ Dump(Stream *s);
+
+ 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 uint32_t
+ FindGlobalVariables(const ConstString &name,
+ bool append,
+ uint32_t max_matches,
+ VariableList& variables);
+
+ virtual uint32_t
+ FindGlobalVariables(const RegularExpression& regex,
+ bool append,
+ uint32_t max_matches,
+ VariableList& variables);
+
+ virtual uint32_t
+ FindFunctions(const ConstString &name,
+ bool append,
+ SymbolContextList& sc_list);
+
+ virtual uint32_t
+ FindFunctions(const RegularExpression& regex,
+ bool append,
+ SymbolContextList& sc_list);
+
+ virtual uint32_t
+ GetNumCompileUnits();
+
+ virtual bool
+ SetCompileUnitAtIndex (lldb::CompUnitSP& cu,
+ uint32_t index);
+
+ virtual lldb::CompUnitSP
+ GetCompileUnitAtIndex(uint32_t idx);
+
+ TypeList&
+ GetTypeList()
+ {
+ return m_type_list;
+ }
+
+ const TypeList&
+ GetTypeList() const
+ {
+ return m_type_list;
+ }
+
+ SymbolFile *
+ GetSymbolFile()
+ {
+ return m_sym_file_ap.get();
+ }
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp (const char *command, Stream *strm);
+
+ virtual Error
+ ExecutePluginCommand (Args &command, Stream *strm);
+
+ virtual Log *
+ EnablePluginLogging (Stream *strm, Args &command);
+
+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;
+
+ mutable Mutex m_mutex;
+ TypeList m_type_list; // Uniqued types for all parsers owned by this module
+ CompileUnits m_compile_units; // The current compile units
+ std::auto_ptr<SymbolFile> m_sym_file_ap; // A single symbol file. Suclasses 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/lldb/include/lldb/Symbol/Symtab.h b/lldb/include/lldb/Symbol/Symtab.h
new file mode 100644
index 00000000000..cb98db92713
--- /dev/null
+++ b/lldb/include/lldb/Symbol/Symtab.h
@@ -0,0 +1,77 @@
+//===-- 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/UniqueCStringMap.h"
+#include "lldb/Symbol/Symbol.h"
+
+namespace lldb_private {
+
+class Symtab
+{
+public:
+ Symtab(ObjectFile *objfile);
+ ~Symtab();
+
+ void Reserve (uint32_t count);
+ Symbol * Resize (uint32_t count);
+ uint32_t AddSymbol(const Symbol& symbol);
+ size_t GetNumSymbols() const;
+ void Dump(Stream *s, Process *process) const;
+ void Dump(Stream *s, Process *process, std::vector<uint32_t>& indexes) const;
+
+ Symbol * SymbolAtIndex (uint32_t idx);
+ const Symbol * SymbolAtIndex (uint32_t idx) const;
+ Symbol * FindSymbolWithType (lldb::SymbolType symbol_type, uint32_t &start_idx);
+ const Symbol * FindSymbolWithType (lldb::SymbolType symbol_type, uint32_t &start_idx) const;
+ uint32_t AppendSymbolIndexesWithType (lldb::SymbolType symbol_type, std::vector<uint32_t>& matches, uint32_t start_idx = 0, uint32_t end_index = UINT_MAX) const;
+ uint32_t AppendSymbolIndexesWithName (const ConstString& symbol_name, std::vector<uint32_t>& matches);
+ uint32_t AppendSymbolIndexesWithNameAndType (const ConstString& symbol_name, lldb::SymbolType symbol_type, std::vector<uint32_t>& matches);
+ uint32_t AppendSymbolIndexesMatchingRegExAndType (const RegularExpression &regex, lldb::SymbolType symbol_type, std::vector<uint32_t>& indexes);
+ size_t FindAllSymbolsWithNameAndType (const ConstString &name, lldb::SymbolType symbol_type, std::vector<uint32_t>& symbol_indexes);
+ size_t FindAllSymbolsMatchingRexExAndType (const RegularExpression &regex, lldb::SymbolType symbol_type, std::vector<uint32_t>& symbol_indexes);
+ Symbol * FindFirstSymbolWithNameAndType (const ConstString &name, lldb::SymbolType symbol_type = lldb::eSymbolTypeAny);
+ Symbol * FindSymbolWithFileAddress (lldb::addr_t file_addr);
+// Symbol * FindSymbolContainingAddress (const Address& value, const uint32_t* indexes, uint32_t num_indexes);
+// Symbol * FindSymbolContainingAddress (const Address& value);
+ Symbol * FindSymbolContainingFileAddress (lldb::addr_t file_addr, const uint32_t* indexes, uint32_t num_indexes);
+ Symbol * FindSymbolContainingFileAddress (lldb::addr_t file_addr);
+ size_t CalculateSymbolSize (Symbol *symbol);
+
+ void SortSymbolIndexesByValue (std::vector<uint32_t>& indexes, bool remove_duplicates) const;
+
+ static void DumpSymbolHeader (Stream *s);
+
+protected:
+ typedef std::vector<Symbol> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ static int CompareSymbolValueByIndex (void *thunk, const void *a, const void *b);
+ void InitNameIndexes ();
+ void InitAddressIndexes ();
+
+ ObjectFile * m_objfile;
+ collection m_symbols;
+ std::vector<uint32_t> m_addr_indexes;
+ UniqueCStringMap<uint32_t> m_name_to_index;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (Symtab);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Symtab_h_
diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h
new file mode 100644
index 00000000000..9d7810af9c0
--- /dev/null
+++ b/lldb/include/lldb/Symbol/Type.h
@@ -0,0 +1,286 @@
+//===-- 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/UserID.h"
+#include "lldb/Symbol/Declaration.h"
+#include <set>
+
+namespace lldb_private {
+
+class Type : public UserID
+{
+public:
+ typedef enum
+ {
+ eTypeInvalid,
+ eIsTypeWithUID, ///< This type is the type whose UID is m_encoding_uid
+ eIsConstTypeWithUID, ///< This type is the type whose UID is m_encoding_uid with the const qualifier added
+ eIsRestrictTypeWithUID, ///< This type is the type whose UID is m_encoding_uid with the restrict qualifier added
+ eIsVolatileTypeWithUID, ///< This type is the type whose UID is m_encoding_uid with the volatile qualifier added
+ eTypedefToTypeWithUID, ///< This type is pointer to a type whose UID is m_encoding_uid
+ ePointerToTypeWithUID, ///< This type is pointer to a type whose UID is m_encoding_uid
+ eLValueReferenceToTypeWithUID, ///< This type is L value reference to a type whose UID is m_encoding_uid
+ eRValueReferenceToTypeWithUID, ///< This type is R value reference to a type whose UID is m_encoding_uid
+ eTypeUIDSynthetic
+ } EncodingUIDType;
+
+ Type(lldb::user_id_t uid,
+ SymbolFile* symbol_file,
+ const ConstString &name,
+ uint64_t byte_size,
+ SymbolContextScope *context,
+ lldb::user_id_t encoding_uid,
+ EncodingUIDType encoding_type,
+ const Declaration& decl,
+ void *clang_qual_type);
+
+ // This makes an invalid type. Used for functions that return a Type when they
+ // get an error.
+ Type();
+
+ const Type&
+ operator= (const Type& rhs);
+
+ void
+ Dump(Stream *s, bool show_context);
+
+ void
+ DumpTypeName(Stream *s);
+
+ 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 != eTypeInvalid;
+ }
+
+ void
+ SetByteSize(uint32_t byte_size);
+
+ const ConstString &
+ GetName () const
+ {
+ return m_name;
+ }
+
+ static ConstString
+ GetClangTypeName (void *clang_qual_type);
+
+ static void
+ DumpValue(ExecutionContext *exe_ctx,
+ clang::ASTContext *ast_context,
+ void *clang_qual_type,
+ Stream *s,
+ lldb::Format format,
+ const DataExtractor &data,
+ uint32_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);
+
+ static void
+ DumpSummary (ExecutionContext *exe_ctx,
+ clang::ASTContext *ast_context,
+ void *clang_qual_type,
+ Stream *s,
+ const DataExtractor &data,
+ uint32_t data_offset,
+ size_t data_byte_size);
+
+
+ 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,
+ lldb::AddressType address_type,
+ bool show_types,
+ bool show_summary,
+ bool verbose);
+
+ static bool
+ DumpTypeValue ( Stream *s,
+ clang::ASTContext *ast_context,
+ void *clang_qual_type,
+ lldb::Format format,
+ const DataExtractor &data,
+ uint32_t data_offset,
+ size_t data_byte_size,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset);
+
+ static bool
+ GetValueAsScalar (clang::ASTContext *ast_context,
+ void *clang_qual_type,
+ const DataExtractor &data,
+ uint32_t data_offset,
+ size_t data_byte_size,
+ Scalar &value);
+
+ static bool
+ SetValueFromScalar (clang::ASTContext *ast_context,
+ void *clang_qual_type,
+ const Scalar &value,
+ Stream &strm);
+
+ bool
+ ReadFromMemory (ExecutionContext *exe_ctx,
+ lldb::addr_t address,
+ lldb::AddressType address_type,
+ DataExtractor &data);
+
+ bool
+ WriteToMemory (ExecutionContext *exe_ctx,
+ lldb::addr_t address,
+ lldb::AddressType address_type,
+ DataExtractor &data);
+
+
+ static bool
+ ReadFromMemory (ExecutionContext *exe_ctx,
+ clang::ASTContext *ast_context,
+ void *clang_qual_type,
+ lldb::addr_t addr,
+ lldb::AddressType address_type,
+ DataExtractor &data);
+
+ static bool
+ WriteToMemory (ExecutionContext *exe_ctx,
+ clang::ASTContext *ast_context,
+ void *clang_qual_type,
+ lldb::addr_t addr,
+ lldb::AddressType address_type,
+ StreamString &new_value);
+
+ bool
+ GetIsDeclaration() const;
+
+ void
+ SetIsDeclaration(bool b);
+
+ bool
+ GetIsExternal() const;
+
+ void
+ SetIsExternal(bool b);
+
+ lldb::Format
+ GetFormat ();
+
+ lldb::Encoding
+ GetEncoding (uint32_t &count);
+
+ static lldb::Encoding
+ GetEncoding (void *clang_qual_type, uint32_t &count);
+
+ SymbolContextScope *
+ GetSymbolContextScope()
+ {
+ return m_context;
+ }
+ const SymbolContextScope *
+ GetSymbolContextScope() const
+ {
+ return m_context;
+ }
+ void
+ SetSymbolContextScope(SymbolContextScope *context)
+ {
+ m_context = context;
+ }
+
+ void *
+ GetOpaqueClangQualType ();
+
+ clang::ASTContext *
+ GetClangAST ();
+
+ ClangASTContext &
+ GetClangASTContext ();
+
+ void *
+ GetChildClangTypeAtIndex (const char *parent_name,
+ uint32_t idx,
+ bool transparent_pointers,
+ bool omit_empty_base_classes,
+ ConstString& name,
+ uint32_t &child_byte_size,
+ int32_t &child_byte_offset,
+ uint32_t &child_bitfield_bit_size,
+ uint32_t &child_bitfield_bit_offset);
+
+ static int
+ Compare(const Type &a, const Type &b);
+
+ static lldb::Format
+ GetFormat (void *clang_qual_type);
+
+ static int
+ DumpClangTypeName(Stream *s, void *clang_qual_type);
+
+protected:
+ ConstString m_name;
+ uint64_t m_byte_size;
+ SymbolFile *m_symbol_file;
+ SymbolContextScope *m_context; // The symbol context in which this type is defined
+ lldb::user_id_t m_encoding_uid;
+ EncodingUIDType m_encoding_uid_type;
+ Declaration m_decl;
+ void *m_clang_qual_type;
+
+ bool ResolveClangType();
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Type_h_
+
diff --git a/lldb/include/lldb/Symbol/TypeList.h b/lldb/include/lldb/Symbol/TypeList.h
new file mode 100644
index 00000000000..9a488dbc8bf
--- /dev/null
+++ b/lldb/include/lldb/Symbol/TypeList.h
@@ -0,0 +1,94 @@
+//===-- 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/ClangASTContext.h"
+#include "lldb/Symbol/Type.h"
+#include <vector>
+
+namespace lldb_private {
+
+class TypeList
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ TypeList(const char *target_triple = NULL);
+
+ virtual
+ ~TypeList();
+
+ void
+ Clear();
+
+ void
+ Dump(Stream *s, bool show_context);
+
+ lldb::TypeSP
+ FindType(lldb::user_id_t uid);
+
+ TypeList
+ FindTypes(const ConstString &name);
+
+ lldb::TypeSP
+ InsertUnique(lldb::TypeSP& type);
+
+ uint32_t
+ GetSize() const;
+
+ lldb::TypeSP
+ GetTypeAtIndex(uint32_t idx);
+
+ //------------------------------------------------------------------
+ // Classes that inherit from TypeList can see and modify these
+ //------------------------------------------------------------------
+ ClangASTContext &
+ GetClangASTContext ();
+
+ void *
+ CreateClangPointerType (Type *type);
+
+ void *
+ CreateClangTypedefType (Type *typedef_type, Type *base_type);
+
+ // For C++98 references (&)
+ void *
+ CreateClangLValueReferenceType (Type *type);
+
+ // For C++0x references (&&)
+ void *
+ CreateClangRValueReferenceType (Type *type);
+
+ void *
+ GetConstClangType (Type *type);
+
+ void *
+ GetRestrictClangType (Type *type);
+
+ void *
+ GetVolatileClangType (Type *type);
+
+private:
+ typedef std::vector<lldb::TypeSP> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ ClangASTContext m_ast; ///< The type abtract syntax tree.
+
+ collection m_types;
+
+ DISALLOW_COPY_AND_ASSIGN (TypeList);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_TypeList_h_
diff --git a/lldb/include/lldb/Symbol/Variable.h b/lldb/include/lldb/Symbol/Variable.h
new file mode 100644
index 00000000000..0844943e9ca
--- /dev/null
+++ b/lldb/include/lldb/Symbol/Variable.h
@@ -0,0 +1,123 @@
+//===-- 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/Expression/DWARFExpression.h"
+#include "lldb/Symbol/Declaration.h"
+#include "lldb/Core/UserID.h"
+
+namespace lldb_private {
+
+class Variable : public UserID
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ Variable(lldb::user_id_t uid,
+ const ConstString& name, Type *type,
+ lldb::ValueType scope,
+ SymbolContextScope *context,
+ Declaration* decl,
+ const DWARFExpression& location,
+ bool external,
+ bool artificial);
+
+ virtual
+ ~Variable();
+
+ void
+ Dump(Stream *s, bool show_context) const;
+
+ const Declaration&
+ GetDeclaration() const
+ {
+ return m_declaration;
+ }
+
+ const ConstString&
+ GetName() const
+ {
+ return m_name;
+ }
+
+ Type *
+ GetType()
+ {
+ return m_type;
+ }
+
+ const Type *
+ GetType() const
+ {
+ return m_type;
+ }
+
+ 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;
+ }
+
+ size_t
+ MemorySize() const;
+
+ void
+ CalculateSymbolContext (SymbolContext *sc);
+
+ bool
+ IsInScope (StackFrame *frame);
+
+protected:
+ ConstString m_name; // Name of the variable
+ Type * m_type; // The type pointer of the variable (int, struct, class, etc)
+ lldb::ValueType m_scope; // global, parameter, local
+ SymbolContextScope *m_context;// 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
+private:
+ Variable(const Variable& rhs);
+ Variable& operator=(const Variable& rhs);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Variable_h_
diff --git a/lldb/include/lldb/Symbol/VariableList.h b/lldb/include/lldb/Symbol/VariableList.h
new file mode 100644
index 00000000000..53d21e659f8
--- /dev/null
+++ b/lldb/include/lldb/Symbol/VariableList.h
@@ -0,0 +1,74 @@
+//===-- 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 (lldb::VariableSP &var_sp);
+
+ void
+ AddVariables(VariableList *variable_list);
+
+ void
+ Clear();
+
+ void
+ Dump(Stream *s, bool show_context) const;
+
+ lldb::VariableSP
+ GetVariableAtIndex(uint32_t idx);
+
+ lldb::VariableSP
+ FindVariable(const ConstString& name);
+
+// const SymbolContext&
+// GetSymbolContext() const
+// {
+// return m_symbol_context;
+// }
+//
+ 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/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h
new file mode 100644
index 00000000000..54b5dc52211
--- /dev/null
+++ b/lldb/include/lldb/Target/ABI.h
@@ -0,0 +1,67 @@
+//===-- 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/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 arg) const = 0;
+
+ virtual bool
+ PrepareNormalCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ ValueList &args) const = 0;
+
+ virtual bool
+ GetArgumentValues (Thread &thread,
+ ValueList &values) const = 0;
+
+ virtual bool
+ GetReturnValue (Thread &thread,
+ Value &value) const = 0;
+
+ static ABI*
+ FindPlugin (const ConstString &triple);
+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/lldb/include/lldb/Target/DynamicLoader.h b/lldb/include/lldb/Target/DynamicLoader.h
new file mode 100644
index 00000000000..9dc0cb6d9bb
--- /dev/null
+++ b/lldb/include/lldb/Target/DynamicLoader.h
@@ -0,0 +1,154 @@
+//===-- 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/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;
+
+ //------------------------------------------------------------------
+ /// Get wether 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 wether 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 wether 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;
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ Process* m_process; ///< The process that this dynamic loader plug-in is tracking.
+ bool m_stop_when_images_change; ///< Boolean value that indicates if the process should stop when imamges change.
+private:
+ DISALLOW_COPY_AND_ASSIGN (DynamicLoader);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_DynamicLoader_h_
diff --git a/lldb/include/lldb/Target/ExecutionContext.h b/lldb/include/lldb/Target/ExecutionContext.h
new file mode 100644
index 00000000000..cc925cff997
--- /dev/null
+++ b/lldb/include/lldb/Target/ExecutionContext.h
@@ -0,0 +1,93 @@
+//===-- ExecutionContext.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef liblldb_ExecutionContext_h_
+#define liblldb_ExecutionContext_h_
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @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 process, thread and frame.
+///
+/// Many lldb functions can evaluate or act upon a specific
+/// execution context. An expression could be evaluated for a specific
+/// process, thread, and frame. The thread object contains frames and
+/// can return StackFrame objects given a valid frame index using:
+/// StackFrame * Thread::GetFrameAtIndex (uint32_t idx).
+//----------------------------------------------------------------------
+class ExecutionContext
+{
+public:
+ //------------------------------------------------------------------
+ /// Default Constructor.
+ ///
+ /// Initialize with NULL process and thread, and invalid frame
+ /// index.
+ //------------------------------------------------------------------
+ ExecutionContext();
+
+
+ ExecutionContext (Target* t, bool fill_current_process_thread_frame = true);
+ //------------------------------------------------------------------
+ /// 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 (ExecutionContextScope *exe_scope);
+
+ ExecutionContext (ExecutionContextScope &exe_scope);
+
+ //------------------------------------------------------------------
+ /// 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;
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ Target *target; ///< The target that owns the process/thread/frame
+ Process *process; ///< The process that owns the thread/frame
+ Thread *thread; ///< The thread that owns the frame
+ StackFrame *frame; ///< The stack frame in thread.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ExecutionContext_h_
diff --git a/lldb/include/lldb/Target/ExecutionContextScope.h b/lldb/include/lldb/Target/ExecutionContextScope.h
new file mode 100644
index 00000000000..f98e3276543
--- /dev/null
+++ b/lldb/include/lldb/Target/ExecutionContextScope.h
@@ -0,0 +1,71 @@
+//===-- 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 Target *
+ CalculateTarget () = 0;
+
+ virtual Process *
+ CalculateProcess () = 0;
+
+ virtual Thread *
+ CalculateThread () = 0;
+
+ virtual StackFrame *
+ 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
+ Calculate (ExecutionContext &exe_ctx) = 0;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ExecutionContextScope_h_
diff --git a/lldb/include/lldb/Target/ObjCObjectPrinter.h b/lldb/include/lldb/Target/ObjCObjectPrinter.h
new file mode 100644
index 00000000000..3b7005b0962
--- /dev/null
+++ b/lldb/include/lldb/Target/ObjCObjectPrinter.h
@@ -0,0 +1,49 @@
+//===-- ObjCObjectPrinter.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ObjCObjectPrinter_h_
+#define liblldb_ObjCObjectPrinter_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+// Project includes
+
+namespace lldb_private {
+
+ class ObjCObjectPrinter
+ {
+ public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ObjCObjectPrinter (Process &process);
+
+ virtual
+ ~ObjCObjectPrinter ();
+
+ bool
+ PrintObject (ConstString &str, Value &object_ptr, ExecutionContext &exe_ctx);
+ protected:
+ Process &m_process;
+ std::auto_ptr<Address> m_PrintForDebugger_addr;
+
+ Address *GetPrintForDebuggerAddr();
+ private:
+ //------------------------------------------------------------------
+ // For ObjCObjectPrinter only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ObjCObjectPrinter);
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_ObjCObjectPrinter_h_
diff --git a/lldb/include/lldb/Target/PathMappingList.h b/lldb/include/lldb/Target/PathMappingList.h
new file mode 100644
index 00000000000..3881437ffd4
--- /dev/null
+++ b/lldb/include/lldb/Target/PathMappingList.h
@@ -0,0 +1,82 @@
+//===-- 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 (ChangedCallback callback,
+ void *callback_baton);
+
+ virtual
+ ~PathMappingList ();
+
+ void
+ Append (const ConstString &path, const ConstString &replacement, bool notify);
+
+ void
+ Clear (bool notify);
+
+ void
+ Dump (Stream *s);
+
+ size_t
+ GetSize ();
+
+ void
+ Insert (const ConstString &path,
+ const ConstString &replacement,
+ uint32_t insert_idx,
+ bool notify);
+
+ bool
+ Remove (off_t index, bool notify);
+
+ bool
+ RemapPath (const ConstString &path, ConstString &new_path);
+
+protected:
+ typedef std::pair <ConstString, ConstString> pair;
+ typedef std::vector <pair> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ collection m_pairs;
+ ChangedCallback m_callback;
+ void * m_callback_baton;
+private:
+ //------------------------------------------------------------------
+ // For PathMappingList only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (PathMappingList);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_PathMappingList_h_
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
new file mode 100644
index 00000000000..30663bd1c52
--- /dev/null
+++ b/lldb/include/lldb/Target/Process.h
@@ -0,0 +1,1415 @@
+//===-- 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
+// C++ Includes
+#include <list>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Core/ThreadSafeSTLMap.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Breakpoint/BreakpointSiteList.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/ObjCObjectPrinter.h"
+#include "lldb/Target/ThreadList.h"
+#include "lldb/Target/UnixSignals.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Process Process.h "lldb/Target/Process.h"
+/// @brief A plug-in interface definition class for debugging a process.
+//----------------------------------------------------------------------
+class Process :
+ public UserID,
+ public Broadcaster,
+ public ExecutionContextScope,
+ public PluginInterface
+{
+friend class ThreadList;
+
+public:
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitStateChanged = (1 << 0),
+ eBroadcastBitInterrupt = (1 << 1),
+ eBroadcastBitSTDOUT = (1 << 2),
+ eBroadcastBitSTDERR = (1 << 3),
+ };
+
+ enum
+ {
+ eBroadcastInternalStateControlStop = (1<<0),
+ eBroadcastInternalStateControlPause = (1<<1),
+ eBroadcastInternalStateControlResume = (1<<2)
+ };
+
+ //------------------------------------------------------------------
+ /// 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
+ {
+ 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;
+
+ lldb::StateType
+ GetState() const;
+
+ bool
+ GetRestarted () const;
+
+ 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 void
+ SetRestartedInEvent (Event *event_ptr, bool new_value);
+
+ static bool
+ SetUpdateStateOnRemoval (Event *event_ptr);
+
+
+ private:
+
+ void
+ SetUpdateStateOnRemoval();
+
+ void
+ SetRestarted (bool new_value);
+
+ lldb::ProcessSP m_process_sp;
+ lldb::StateType m_state;
+ bool m_restarted; // For "eStateStopped" events, this is true if the target was automatically restarted.
+ bool m_update_state;
+ DISALLOW_COPY_AND_ASSIGN (ProcessEventData);
+
+ };
+#endif
+
+ //------------------------------------------------------------------
+ /// 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 Process*
+ FindPlugin (Target &target, const char *plugin_name, Listener &listener);
+
+
+
+ //------------------------------------------------------------------
+ /// 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
+ int signo, // Zero for no signal
+ int status); // Exit value of process if signal is zero
+
+ //------------------------------------------------------------------
+ /// Check if a plug-in instance can debug the file in \a module.
+ ///
+ /// Each plug-in is given a chance to say wether 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) = 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();
+
+ //------------------------------------------------------------------
+ /// 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] 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.
+ ///
+ /// @return
+ /// An error object. Call GetID() to get the process ID if
+ /// the error object is success.
+ //------------------------------------------------------------------
+ virtual Error
+ Launch (char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path);
+
+ //------------------------------------------------------------------
+ /// Attach to an existing process using a process ID.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses. It will first call Process::WillAttach (lldb::pid_t)
+ /// and if that returns \b true, Process::DoAttach (lldb::pid_t) 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 (lldb::pid_t pid);
+
+ //------------------------------------------------------------------
+ /// 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 Error
+ Attach (const char *process_name, bool wait_for_launch);
+
+ uint32_t
+ GetAddressByteSize();
+
+ //------------------------------------------------------------------
+ /// 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 ();
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @return
+ /// Returns an error object.
+ ///
+ /// @see Thread:Resume()
+ /// @see Thread:Step()
+ /// @see Thread:Suspend()
+ //------------------------------------------------------------------
+ virtual Error
+ Resume ();
+
+ //------------------------------------------------------------------
+ /// Halts a running process.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ Halt ();
+
+ //------------------------------------------------------------------
+ /// Detaches from a running or stopped process.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ Detach ();
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ virtual 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.
+ //------------------------------------------------------------------
+ virtual Error
+ Signal (int signal);
+
+ virtual UnixSignals &
+ GetUnixSignals ();
+
+
+ //==================================================================
+ // 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
+ WillAttach (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
+ WillAttach (const char *process_name, bool wait_for_launch)
+ {
+ 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
+ DoAttach (lldb::pid_t pid) = 0;
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @return
+ /// Returns \a pid if attaching was successful, or
+ /// LLDB_INVALID_PROCESS_ID if attaching fails.
+ //------------------------------------------------------------------
+ virtual Error
+ DoAttach (const char *process_name, bool wait_for_launch)
+ {
+ 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 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] 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.
+ ///
+ /// @return
+ /// A new valid process ID, or LLDB_INVALID_PROCESS_ID if
+ /// launching fails.
+ //------------------------------------------------------------------
+ virtual Error
+ DoLaunch (Module* module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path) = 0;
+
+ //------------------------------------------------------------------
+ /// 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 () = 0;
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @return
+ /// Returns \b true if the process successfully halts, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ virtual Error
+ DoHalt () = 0;
+
+ //------------------------------------------------------------------
+ /// 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 () = 0;
+
+ //------------------------------------------------------------------
+ /// Called after detaching from a process.
+ ///
+ /// Allow Process plug-ins to execute some code after detaching
+ /// from a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidDetach () {}
+
+ //------------------------------------------------------------------
+ /// 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) = 0;
+
+
+
+ virtual Error
+ WillDestroy () { return Error(); }
+
+ virtual Error
+ DoDestroy () = 0;
+
+ virtual void
+ DidDestroy () { }
+
+
+ //------------------------------------------------------------------
+ /// 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 ();
+
+ //------------------------------------------------------------------
+ /// 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;
+
+ //------------------------------------------------------------------
+ /// Get accessor for the current process state.
+ ///
+ /// @return
+ /// The current state of the process.
+ ///
+ /// @see lldb::StateType
+ //------------------------------------------------------------------
+ lldb::StateType
+ GetState ();
+
+protected:
+ friend class CommandObjectProcessLaunch;
+ friend class ProcessEventData;
+ friend class CommandObjectBreakpointCommand;
+
+ void
+ SetState (lldb::EventSP &event_sp);
+
+ lldb::StateType
+ GetPrivateState ();
+
+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 number of times this process has posted a stop event.
+ ///
+ /// @return
+ /// The number of times this process has stopped while being
+ /// debugged.
+ //------------------------------------------------------------------
+ uint32_t
+ GetStopID () const;
+
+ //------------------------------------------------------------------
+ /// 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 void
+ 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;
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ size_t
+ ReadMemory (lldb::addr_t vm_addr,
+ void *buf,
+ size_t size,
+ 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.
+ ///
+ /// @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) = 0;
+
+ //------------------------------------------------------------------
+ /// 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) = 0;
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @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);
+
+ //------------------------------------------------------------------
+ /// 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) = 0;
+
+ //------------------------------------------------------------------
+ /// 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)
+ {
+ error.SetErrorString("stdout unsupported");
+ return 0;
+ }
+
+
+ //------------------------------------------------------------------
+ /// 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)
+ {
+ error.SetErrorString("stderr unsupported");
+ return 0;
+ }
+
+ virtual size_t
+ PutSTDIN (const char *buf, size_t buf_size, Error &error)
+ {
+ error.SetErrorString("stdin unsupported");
+ return 0;
+ }
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode (BreakpointSite* bp_site) = 0;
+
+ virtual Error
+ EnableBreakpoint (BreakpointSite *bp_site) = 0;
+
+ virtual Error
+ DisableBreakpoint (BreakpointSite *bp_site) = 0;
+
+ // 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::user_id_t
+ CreateBreakpointSite (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. This has to
+ // be a static function because you can't be sure that removing the
+ // breakpoint from it's containing map won't delete the breakpoint site,
+ // and doing that in an instance method isn't copasetic.
+ 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 (WatchpointLocation *bp_loc);
+
+ virtual Error
+ DisableWatchpoint (WatchpointLocation *bp_loc);
+
+ //------------------------------------------------------------------
+ // Thread Queries
+ //------------------------------------------------------------------
+ virtual uint32_t
+ UpdateThreadListIfNeeded () = 0;
+
+ ThreadList &
+ GetThreadList ();
+
+ const ThreadList &
+ GetThreadList () const;
+
+ uint32_t
+ GetNextThreadIndexID ();
+
+ //------------------------------------------------------------------
+ // Event Handling
+ //------------------------------------------------------------------
+ lldb::StateType
+ GetNextEvent (lldb::EventSP &event_sp);
+
+ lldb::StateType
+ WaitForProcessToStop (const TimeValue *timeout);
+
+ lldb::StateType
+ WaitForStateChangedEvents (const TimeValue *timeout, lldb::EventSP &event_sp);
+
+ Event *
+ PeekAtStateChangedEvents ();
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @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);
+
+ //------------------------------------------------------------------
+ /// Gets the byte order for this process.
+ ///
+ /// @return
+ /// A valid ByteOrder enumeration, or eByteOrderInvalid.
+ //------------------------------------------------------------------
+ virtual lldb::ByteOrder
+ GetByteOrder () const = 0;
+
+ const ConstString &
+ GetTargetTriple ()
+ {
+ return m_target_triple;
+ }
+
+ const ABI *
+ GetABI ();
+
+ virtual DynamicLoader *
+ GetDynamicLoader ();
+
+ lldb::addr_t
+ GetSectionLoadAddress (const Section *section) const;
+
+ bool
+ ResolveLoadAddress (lldb::addr_t load_addr, Address &so_addr) const;
+
+ bool
+ SectionLoaded (const Section *section, lldb::addr_t load_addr);
+
+ // 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
+ SectionUnloaded (const Section *section, 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
+ SectionUnloaded (const Section *section);
+
+ bool
+ IsRunning () const;
+
+ //------------------------------------------------------------------
+ // lldb::ExecutionContextScope pure virtual functions
+ //------------------------------------------------------------------
+ virtual Target *
+ CalculateTarget ();
+
+ virtual Process *
+ CalculateProcess ();
+
+ virtual Thread *
+ CalculateThread ();
+
+ virtual StackFrame *
+ CalculateStackFrame ();
+
+ virtual void
+ Calculate (ExecutionContext &exe_ctx);
+
+ lldb::ProcessSP
+ GetSP ();
+
+ ObjCObjectPrinter &
+ GetObjCObjectPrinter();
+
+protected:
+ typedef ThreadSafeSTLMap<lldb::addr_t, const Section *> SectionLoadColl;
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ Target & m_target; ///< The target that owns this process.
+ SectionLoadColl m_section_load_info; ///< A mapping of all currently loaded sections.
+ 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
+ uint32_t m_stop_id; ///< A count of many times the process has stopped.
+ uint32_t m_thread_index_id; ///< Each thread is created with a 1 based index that won't get re-used.
+ 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.
+ ThreadList m_thread_list; ///< The threads for this process.
+ std::vector<Notifications> m_notifications; ///< The list of notifications that this process can deliver.
+ Listener &m_listener;
+ BreakpointSiteList m_breakpoint_site_list; ///< This is the list of breakpoint locations we intend
+ ///< to insert in the target.
+ UnixSignals m_unix_signals; /// This is the current signal set for this process.
+ ConstString m_target_triple;
+ lldb::ABISP m_abi_sp;
+ ObjCObjectPrinter m_objc_object_printer;
+
+ 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);
+
+ void
+ SetPrivateState (lldb::StateType state);
+
+ bool
+ StartPrivateStateThread ();
+
+ 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);
+
+ Error
+ CompleteAttach ();
+
+
+ // 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);
+
+private:
+ //------------------------------------------------------------------
+ // For Process only
+ //------------------------------------------------------------------
+ void ControlPrivateStateThread (uint32_t signal);
+ DISALLOW_COPY_AND_ASSIGN (Process);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Process_h_
diff --git a/lldb/include/lldb/Target/RegisterContext.h b/lldb/include/lldb/Target/RegisterContext.h
new file mode 100644
index 00000000000..5c646cf600b
--- /dev/null
+++ b/lldb/include/lldb/Target/RegisterContext.h
@@ -0,0 +1,172 @@
+//===-- 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 ExecutionContextScope
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContext (Thread &thread, StackFrame *frame);
+
+ virtual
+ ~RegisterContext ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ Invalidate () = 0;
+
+ virtual size_t
+ GetRegisterCount () = 0;
+
+ virtual const lldb::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg) = 0;
+
+ virtual size_t
+ GetRegisterSetCount () = 0;
+
+ virtual const lldb::RegisterSet *
+ GetRegisterSet (uint32_t reg_set) = 0;
+
+ virtual bool
+ ReadRegisterValue (uint32_t reg, Scalar &value) = 0;
+
+ virtual bool
+ ReadRegisterBytes (uint32_t reg, DataExtractor &data) = 0;
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp) = 0;
+
+ virtual bool
+ WriteRegisterValue (uint32_t reg, const Scalar &value) = 0;
+
+ virtual bool
+ WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset = 0) = 0;
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) = 0;
+
+ 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);
+
+ //------------------------------------------------------------------
+ // Subclasses should not override these
+ //------------------------------------------------------------------
+ lldb::tid_t
+ GetThreadID() const;
+
+ const lldb::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);
+
+ bool
+ WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval);
+
+ //------------------------------------------------------------------
+ // lldb::ExecutionContextScope pure virtual functions
+ //------------------------------------------------------------------
+ virtual Target *
+ CalculateTarget ();
+
+ virtual Process *
+ CalculateProcess ();
+
+ virtual Thread *
+ CalculateThread ();
+
+ virtual StackFrame *
+ CalculateStackFrame ();
+
+ virtual void
+ Calculate (ExecutionContext &exe_ctx);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from RegisterContext can see and modify these
+ //------------------------------------------------------------------
+ Thread &m_thread; // The thread that this register context belongs to.
+ StackFrame *m_frame; // The stack frame for this context, or NULL if this is the root context
+private:
+ //------------------------------------------------------------------
+ // For RegisterContext only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (RegisterContext);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_RegisterContext_h_
diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h
new file mode 100644
index 00000000000..0c46ec278eb
--- /dev/null
+++ b/lldb/include/lldb/Target/StackFrame.h
@@ -0,0 +1,126 @@
+//===-- 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 UserID,
+ public ExecutionContextScope
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StackFrame (lldb::user_id_t frame_idx, Thread &thread, lldb::addr_t cfa, lldb::addr_t pc, const SymbolContext *sc_ptr = NULL);
+ StackFrame (lldb::user_id_t frame_idx, Thread &thread, lldb::RegisterContextSP &reg_context_sp, lldb::addr_t cfa, lldb::addr_t pc, const SymbolContext *sc_ptr = NULL);
+ virtual ~StackFrame ();
+
+ Thread &
+ GetThread()
+ { return m_thread; }
+
+ const Thread &
+ GetThread() const
+ { return m_thread; }
+
+ StackID&
+ GetStackID();
+
+ Address&
+ GetPC();
+
+ void
+ ChangePC (lldb::addr_t pc);
+
+ const SymbolContext&
+ GetSymbolContext (uint32_t resolve_scope);
+
+ bool
+ GetFrameBaseValue(Scalar &value, Error *error_ptr);
+
+ RegisterContext *
+ GetRegisterContext ();
+
+ VariableList *
+ GetVariableList ();
+
+ bool
+ HasDebugInformation ();
+
+ ValueObjectList &
+ GetValueObjectList();
+
+ const char *
+ Disassemble ();
+
+ void
+ Dump (Stream *strm, bool show_frame_index);
+
+ //------------------------------------------------------------------
+ // lldb::ExecutionContextScope pure virtual functions
+ //------------------------------------------------------------------
+ virtual Target *
+ CalculateTarget ();
+
+ virtual Process *
+ CalculateProcess ();
+
+ virtual Thread *
+ CalculateThread ();
+
+ virtual StackFrame *
+ CalculateStackFrame ();
+
+ virtual void
+ Calculate (ExecutionContext &exe_ctx);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from StackFrame can see and modify these
+ //------------------------------------------------------------------
+
+
+private:
+ //------------------------------------------------------------------
+ // For StackFrame only
+ //------------------------------------------------------------------
+ Thread &m_thread;
+ lldb::RegisterContextSP m_reg_context_sp;
+ StackID m_id;
+ Address m_pc; // PC 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_value_object_list;
+ StreamString m_disassembly;
+ DISALLOW_COPY_AND_ASSIGN (StackFrame);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StackFrame_h_
diff --git a/lldb/include/lldb/Target/StackFrameList.h b/lldb/include/lldb/Target/StackFrameList.h
new file mode 100644
index 00000000000..678bff5a3d8
--- /dev/null
+++ b/lldb/include/lldb/Target/StackFrameList.h
@@ -0,0 +1,88 @@
+//===-- 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:
+ friend class Thread;
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StackFrameList();
+
+ virtual
+ ~StackFrameList();
+
+ uint32_t
+ GetNumFrames() const;
+
+ lldb::StackFrameSP
+ GetFrameAtIndex (uint32_t idx) const;
+
+ bool
+ SetFrameAtIndex (uint32_t idx, lldb::StackFrameSP &frame_sp);
+
+ // Mark a stack frame as the current frame
+ uint32_t
+ SetCurrentFrame (lldb_private::StackFrame *frame);
+
+ uint32_t
+ GetCurrentFrameIndex () const;
+
+ // Mark a stack frame as the current frame using the frame index
+ void
+ SetCurrentFrameByIndex (uint32_t idx);
+
+ void
+ Clear ();
+
+ // After we have determined the number of frames, we can set the count here
+ // and have the frame info be generated on demand.
+ void
+ SetNumFrames(uint32_t count);
+
+ void
+ InvalidateFrames (uint32_t start_idx);
+protected:
+
+ //------------------------------------------------------------------
+ // 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;
+
+ mutable Mutex m_mutex;
+ collection m_frames;
+ uint32_t m_current_frame_idx;
+
+private:
+ //------------------------------------------------------------------
+ // For StackFrameList only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (StackFrameList);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StackFrameList_h_
diff --git a/lldb/include/lldb/Target/StackID.h b/lldb/include/lldb/Target/StackID.h
new file mode 100644
index 00000000000..cf02be1c925
--- /dev/null
+++ b/lldb/include/lldb/Target/StackID.h
@@ -0,0 +1,65 @@
+//===-- 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 ();
+ explicit StackID (lldb::addr_t cfa);
+ StackID (const Address& start_address, lldb::addr_t cfa);
+ StackID (const StackID& rhs);
+ virtual ~StackID();
+
+ const Address&
+ GetStartAddress() const;
+
+ void
+ SetStartAddress(const Address& start_address);
+
+ lldb::addr_t
+ GetCallFrameAddress() const;
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const StackID&
+ operator=(const StackID& rhs);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from StackID can see and modify these
+ //------------------------------------------------------------------
+ Address m_start_address; // The address range for the function for this frame
+ lldb::addr_t m_cfa; // The call frame address (stack pointer) value
+ // at the beginning of the function that uniquely
+ // identifies this frame
+};
+
+bool operator== (const StackID& lhs, const StackID& rhs);
+bool operator!= (const StackID& lhs, const StackID& rhs);
+bool operator< (const StackID& lhs, const StackID& rhs);
+
+} // namespace lldb_private
+
+#endif // liblldb_StackID_h_
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
new file mode 100644
index 00000000000..0f9fd09b985
--- /dev/null
+++ b/lldb/include/lldb/Target/Target.h
@@ -0,0 +1,324 @@
+//===-- 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
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Breakpoint/BreakpointList.h"
+#include "lldb/Breakpoint/BreakpointLocationCollection.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/PathMappingList.h"
+
+#include "lldb/API/SBTarget.h"
+
+namespace lldb_private {
+
+class Target :
+ public Broadcaster,
+ public ExecutionContextScope
+{
+public:
+ friend class TargetList;
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitBreakpointChanged = (1 << 0),
+ eBroadcastBitModulesLoaded = (1 << 1),
+ eBroadcastBitModulesUnloaded = (1 << 2)
+ };
+
+ lldb::ModuleSP
+ GetSharedModule (const FileSpec& file_spec,
+ const ArchSpec& arch,
+ const UUID *uuid = NULL,
+ const ConstString *object_name = NULL,
+ off_t object_offset = 0,
+ Error *error_ptr = NULL);
+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();
+
+public:
+ ~Target();
+
+ void
+ DeleteCurrentProcess ();
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ const lldb::ProcessSP &
+ CreateProcess (Listener &listener, const char *plugin_name = NULL);
+
+ const lldb::ProcessSP &
+ GetProcessSP () const;
+
+ lldb::TargetSP
+ GetSP();
+
+
+ //------------------------------------------------------------------
+ // This part handles the breakpoints.
+ //------------------------------------------------------------------
+
+ BreakpointList &
+ GetBreakpointList(bool internal = false);
+
+ const BreakpointList &
+ GetBreakpointList(bool internal = false) const;
+
+ 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 FileSpec *containingModule,
+ const FileSpec &file,
+ uint32_t line_no,
+ bool check_inlines,
+ 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, or all modules if it is NULL
+ lldb::BreakpointSP
+ CreateBreakpoint (FileSpec *containingModule,
+ RegularExpression &func_regexp,
+ bool internal = false);
+
+ // Use this to create a function breakpoint by name in containingModule, or all modules if it is NULL
+ lldb::BreakpointSP
+ CreateBreakpoint (FileSpec *containingModule,
+ const char *func_name,
+ bool internal = false);
+
+ // Use this to create a general breakpoint:
+ lldb::BreakpointSP
+ CreateBreakpoint (lldb::SearchFilterSP &filter_sp,
+ lldb::BreakpointResolverSP &resolver_sp,
+ bool internal = false);
+
+ 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);
+
+ void
+ ModulesDidLoad (ModuleList &module_list);
+
+ void
+ ModulesDidUnload (ModuleList &module_list);
+
+protected:
+ void
+ ModuleAdded (lldb::ModuleSP &module_sp);
+
+ void
+ ModuleUpdated (lldb::ModuleSP &old_module_sp, lldb::ModuleSP &new_module_sp);
+
+public:
+ //------------------------------------------------------------------
+ /// 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 ();
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ ModuleList&
+ GetImages ();
+
+ ArchSpec
+ GetArchitecture () const;
+
+ bool
+ GetTargetTriple (ConstString &target_triple);
+
+ size_t
+ ReadMemory (lldb::AddressType addr_type,
+ lldb::addr_t addr,
+ void *buf,
+ size_t size,
+ Error &error,
+ ObjectFile* objfile = NULL);
+
+ //------------------------------------------------------------------
+ // lldb::ExecutionContextScope pure virtual functions
+ //------------------------------------------------------------------
+ virtual Target *
+ CalculateTarget ();
+
+ virtual Process *
+ CalculateProcess ();
+
+ virtual Thread *
+ CalculateThread ();
+
+ virtual StackFrame *
+ CalculateStackFrame ();
+
+ virtual void
+ Calculate (ExecutionContext &exe_ctx);
+
+ PathMappingList &
+ GetImageSearchPathList ();
+
+ ClangASTContext *
+ GetScratchClangASTContext();
+
+protected:
+ friend class lldb::SBTarget;
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ ModuleList m_images; ///< The list of images for this process (shared libraries and anything dynamically loaded).
+ BreakpointList m_breakpoint_list;
+ BreakpointList m_internal_breakpoint_list;
+ // 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;
+ ConstString m_triple; ///< The target triple ("x86_64-apple-darwin10")
+ lldb::SearchFilterSP m_search_filter_sp;
+ PathMappingList m_image_search_paths;
+ std::auto_ptr<ClangASTContext> m_scratch_ast_context_ap;
+ //------------------------------------------------------------------
+ // Methods.
+ //------------------------------------------------------------------
+ lldb::SearchFilterSP
+ GetSearchFilterForModule (const FileSpec *containingModule);
+
+ 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/lldb/include/lldb/Target/TargetList.h b/lldb/include/lldb/Target/TargetList.h
new file mode 100644
index 00000000000..8cd7b7b971d
--- /dev/null
+++ b/lldb/include/lldb/Target/TargetList.h
@@ -0,0 +1,206 @@
+//===-- 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();
+
+public:
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitInterrupt = (1 << 0)
+ };
+
+
+ ~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] 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] arch
+ /// The architecture to use when launching the \a file_spec for
+ /// debugging. This can be NULL if the architecture is not known
+ /// or when attaching to a process.
+ ///
+ /// @param[in] uuid_ptr
+ /// An optional UUID to use when loading a target. When this is
+ /// specified, plug-ins might be able to track down a different
+ /// executable than the one on disk specified by "file_spec" in
+ /// an alternate SDK or build location (such as when doing
+ /// symbolication on non-native OS builds).
+ ///
+ /// @return
+ /// A shared pointer to a target object.
+ //------------------------------------------------------------------
+ Error
+ CreateTarget (const FileSpec& file_spec,
+ const ArchSpec& arch,
+ const UUID *uuid_ptr,
+ bool get_dependent_files,
+ 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;
+
+ //------------------------------------------------------------------
+ /// 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
+ SetCurrentTarget (Target *target);
+
+ void
+ SetCurrentTargetWithIndex (uint32_t idx);
+
+ lldb::TargetSP
+ GetCurrentTarget ();
+
+
+protected:
+ typedef std::vector<lldb::TargetSP> collection;
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ collection m_target_list;
+ mutable Mutex m_target_list_mutex;
+ uint32_t m_current_target_idx;
+private:
+ DISALLOW_COPY_AND_ASSIGN (TargetList);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_TargetList_h_
diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h
new file mode 100644
index 00000000000..cc5dcf89db0
--- /dev/null
+++ b/lldb/include/lldb/Target/Thread.h
@@ -0,0 +1,701 @@
+//===-- 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/UserID.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/StackFrameList.h"
+
+#define LLDB_THREAD_MAX_STOP_EXC_DATA 8
+
+// I forward declare these here so I don't have to #include ThreadPlan, so in turn I
+// can use Thread.h in ThreadPlan.h.
+
+namespace lldb_private {
+
+class Thread :
+ public UserID,
+ public ExecutionContextScope
+{
+friend class ThreadPlan;
+public:
+ //----------------------------------------------------------------------
+ // StopInfo
+ //
+ // Describes the reason the thread it was created with stopped.
+ //----------------------------------------------------------------------
+ class StopInfo
+ {
+ public:
+ StopInfo(Thread *thread = NULL);
+
+ ~StopInfo();
+
+ // Clear clears the stop reason, but it does not clear the thread this
+ // StopInfo is tied to.
+ void
+ Clear();
+
+ lldb::StopReason
+ GetStopReason() const;
+
+ void
+ SetThread (Thread *thread);
+
+ Thread *
+ GetThread ();
+
+ void
+ SetStopReasonWithBreakpointSiteID (lldb::user_id_t break_id);
+
+ void
+ SetStopReasonWithWatchpointID (lldb::user_id_t watch_id);
+
+ void
+ SetStopReasonWithSignal (int signo);
+
+ void
+ SetStopReasonToTrace ();
+
+ void
+ SetStopReasonWithException (uint32_t exc_type, size_t exc_data_count);
+
+ void
+ SetStopReasonWithPlan (lldb::ThreadPlanSP &plan);
+
+ void
+ SetStopReasonToNone ();
+
+ const char *
+ GetStopDescription() const;
+
+ void
+ SetStopDescription(const char *desc);
+
+ lldb::user_id_t
+ GetBreakpointSiteID() const;
+
+ lldb::user_id_t
+ GetWatchpointID() const;
+
+ int
+ GetSignal() const;
+
+ lldb::user_id_t
+ GetPlanID () const;
+
+ uint32_t
+ GetExceptionType() const;
+
+ size_t
+ GetExceptionDataCount() const;
+
+ lldb::addr_t
+ GetExceptionDataAtIndex (uint32_t idx) const;
+
+ bool
+ SetExceptionDataAtIndex (uint32_t idx, lldb::addr_t data);
+
+ void
+ Dump (Stream *s) const;
+
+ protected:
+ lldb::StopReason m_reason;
+ //--------------------------------------------------------------
+ // For eStopReasonPlan the completed plan is stored in this shared pointer.
+ //--------------------------------------------------------------
+ lldb::ThreadPlanSP m_completed_plan_sp;
+ Thread *m_thread;
+ char m_description[256];
+ union
+ {
+ //--------------------------------------------------------------
+ // eStopReasonBreakpoint
+ //--------------------------------------------------------------
+ struct
+ {
+ lldb::user_id_t bp_site_id;
+ } breakpoint;
+ //--------------------------------------------------------------
+ // eStopReasonWatchpoint
+ //--------------------------------------------------------------
+ struct
+ {
+ lldb::user_id_t watch_id;
+ } watchpoint;
+ //--------------------------------------------------------------
+ // eStopReasonSignal
+ //--------------------------------------------------------------
+ struct
+ {
+ int signo;
+ } signal;
+ //--------------------------------------------------------------
+ // eStopReasonException
+ //--------------------------------------------------------------
+ struct
+ {
+ uint32_t type;
+ size_t data_count;
+ lldb::addr_t data[LLDB_THREAD_MAX_STOP_EXC_DATA];
+ } exception;
+ } m_details;
+ };
+
+ 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 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;
+ };
+
+ Thread (Process &process, lldb::tid_t tid);
+ virtual ~Thread();
+
+ Process &
+ GetProcess() { return m_process; }
+
+ const Process &
+ GetProcess() const { return m_process; }
+
+ int
+ GetResumeSignal () const;
+
+ void
+ SetResumeSignal (int signal);
+
+ lldb::StateType
+ GetState() const;
+
+ lldb::ThreadSP
+ GetSP ();
+
+ void
+ SetState (lldb::StateType state);
+
+ lldb::StateType
+ GetResumeState () const;
+
+ void
+ SetResumeState (lldb::StateType state);
+
+ // This function is called on all the threads before "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 ();
+
+ // Override this to do platform specific tasks before resume, but always
+ // call the Thread::WillResume at the end of your work.
+
+ virtual bool
+ 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 ();
+
+ virtual void
+ RefreshStateAfterStop() = 0;
+
+ void
+ WillStop ();
+
+ bool
+ ShouldStop (Event *event_ptr);
+
+ lldb::Vote
+ ShouldReportStop (Event *event_ptr);
+
+ lldb::Vote
+ ShouldReportRun (Event *event_ptr);
+
+ bool
+ GetStopInfo (StopInfo *stop_info);
+
+ bool
+ ThreadStoppedForAReason ();
+
+ virtual const char *
+ GetInfo () = 0;
+
+ virtual const char *
+ GetName ()
+ {
+ return NULL;
+ }
+
+ virtual const char *
+ GetQueueName ()
+ {
+ return NULL;
+ }
+
+ virtual uint32_t
+ GetStackFrameCount() = 0;
+
+ virtual lldb::StackFrameSP
+ GetStackFrameAtIndex (uint32_t idx) = 0;
+
+ lldb::StackFrameSP
+ GetCurrentFrame ();
+
+ uint32_t
+ SetCurrentFrame (lldb_private::StackFrame *frame);
+
+ void
+ SetCurrentFrameByIndex (uint32_t frame_idx);
+
+ virtual RegisterContext *
+ GetRegisterContext () = 0;
+
+ virtual bool
+ SaveFrameZeroState (RegisterCheckpoint &checkpoint) = 0;
+
+ virtual bool
+ RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint) = 0;
+
+ virtual RegisterContext *
+ CreateRegisterContextForFrame (StackFrame *frame) = 0;
+
+ virtual void
+ ClearStackFrames ()
+ {
+ m_frames.Clear();
+ }
+
+ void
+ DumpInfo (Stream &strm,
+ bool show_stop_reason,
+ bool show_name,
+ bool show_queue,
+ uint32_t frame_idx);// = UINT32_MAX);
+
+ //------------------------------------------------------------------
+ // 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.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// 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 pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual ThreadPlan *
+ 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 pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual ThreadPlan *
+ 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 pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual ThreadPlan *
+ QueueThreadPlanForStepSingleInstruction (bool step_over,
+ bool abort_other_plans,
+ bool stop_other_threads);
+
+ //------------------------------------------------------------------
+ /// Queues the plan used to step through an address range, stepping into or over
+ /// function calls depending on the value of StepType.
+ ///
+ /// @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 pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual ThreadPlan *
+ QueueThreadPlanForStepRange (bool abort_other_plans,
+ lldb::StepType type,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_other_threads);
+
+ //------------------------------------------------------------------
+ /// 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 pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual ThreadPlan *
+ QueueThreadPlanForStepOut (bool abort_other_plans,
+ SymbolContext *addr_context,
+ bool first_insn,
+ bool stop_other_threads,
+ lldb::Vote stop_vote = lldb::eVoteYes,
+ lldb::Vote run_vote = lldb::eVoteNoOpinion);
+
+ //------------------------------------------------------------------
+ /// 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] 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 pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual ThreadPlan *
+ QueueThreadPlanForStepThrough (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] 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 pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual ThreadPlan *
+ QueueThreadPlanForContinue (bool abort_other_plans,
+ bool stop_other_threads,
+ lldb::Vote stop_vote,
+ lldb::Vote run_vote = lldb::eVoteNoOpinion,
+ bool immediate = false);
+ //------------------------------------------------------------------
+ /// 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 pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual ThreadPlan *
+ QueueThreadPlanForRunToAddress (bool abort_other_plans,
+ Address &target_addr,
+ bool stop_other_threads);
+
+ virtual ThreadPlan *
+ QueueThreadPlanForStepUntil (bool abort_other_plans,
+ lldb::addr_t *address_list,
+ size_t num_addresses,
+ bool stop_others);
+
+ virtual ThreadPlan *
+ QueueThreadPlanForCallFunction (bool abort_other_plans,
+ Address& function,
+ lldb::addr_t arg,
+ bool stop_other_threads,
+ bool discard_on_error = false);
+
+ virtual ThreadPlan *
+ QueueThreadPlanForCallFunction (bool abort_other_plans,
+ Address& function,
+ ValueList &args,
+ bool stop_other_threads,
+ bool discard_on_error = false);
+
+ //------------------------------------------------------------------
+ // Thread Plan accessors:
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Gets the plan which will execute next on the plan stack.
+ ///
+ /// @return
+ /// A pointer to the next executed plan.
+ //------------------------------------------------------------------
+ ThreadPlan *
+ GetCurrentPlan ();
+
+ //------------------------------------------------------------------
+ /// Gets the inner-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 ();
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// Prints the current plan stack.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the plan stack info.
+ ///
+ //------------------------------------------------------------------
+ void
+ DumpThreadPlans (Stream *s) const;
+
+ // 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;
+
+ //------------------------------------------------------------------
+ // lldb::ExecutionContextScope pure virtual functions
+ //------------------------------------------------------------------
+ virtual Target *
+ CalculateTarget ();
+
+ virtual Process *
+ CalculateProcess ();
+
+ virtual Thread *
+ CalculateThread ();
+
+ virtual StackFrame *
+ CalculateStackFrame ();
+
+ virtual void
+ Calculate (ExecutionContext &exe_ctx);
+
+protected:
+ void
+ PushPlan (lldb::ThreadPlanSP &plan_sp);
+
+ void
+ PopPlan ();
+
+ void
+ DiscardPlan ();
+
+ ThreadPlan *GetPreviousPlan (ThreadPlan *plan);
+
+ virtual bool
+ GetRawStopReason (StopInfo *stop_info) = 0;
+
+ typedef std::vector<lldb::ThreadPlanSP> plan_stack;
+
+ //------------------------------------------------------------------
+ // Classes that inherit from Process can see and modify these
+ //------------------------------------------------------------------
+ Process & m_process; ///< The process that owns this thread.
+ 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.
+ plan_stack m_plan_stack; ///< The stack of plans this thread is executing.
+ plan_stack m_immediate_plan_stack; ///< The plans that need to get executed before any other work gets done.
+ 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_state_mutex; ///< Multithreaded protection for m_state.
+ StackFrameList m_frames; ///< The stack frames that get lazily populated after a thread stops.
+ uint32_t m_current_frame_idx;///< The current frame for this thread
+ int m_resume_signal; ///< The signal that should be used when continuing this thread.
+ lldb::StateType m_resume_state; ///< The state that indicates what this thread should do when the process is resumed.
+private:
+ //------------------------------------------------------------------
+ // For Thread only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (Thread);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Thread_h_
diff --git a/lldb/include/lldb/Target/ThreadList.h b/lldb/include/lldb/Target/ThreadList.h
new file mode 100644
index 00000000000..4f82cc7ca65
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadList.h
@@ -0,0 +1,120 @@
+//===-- 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/Host/Mutex.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 (lldb::ThreadSP &thread_sp);
+
+ lldb::ThreadSP
+ GetCurrentThread ();
+
+ bool
+ SetCurrentThreadByID (lldb::tid_t tid);
+
+ bool
+ SetCurrentThreadByIndexID (uint32_t index_id);
+
+ void
+ Clear();
+
+ // 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
+ FindThreadByIndexID (lldb::tid_t index_id, bool can_update = true);
+
+ lldb::ThreadSP
+ GetThreadSPForThreadPtr (Thread *thread_ptr);
+
+ bool
+ ShouldStop (Event *event_ptr);
+
+ lldb::Vote
+ ShouldReportStop (Event *event_ptr);
+
+ lldb::Vote
+ ShouldReportRun (Event *event_ptr);
+
+ void
+ RefreshStateAfterStop ();
+
+ bool
+ WillResume ();
+
+ void
+ DidResume ();
+
+ void
+ DiscardThreadPlans();
+
+ uint32_t
+ GetStopID () const;
+
+ void
+ SetStopID (uint32_t stop_id);
+
+protected:
+
+ 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.
+ mutable Mutex m_threads_mutex;
+ lldb::tid_t m_current_tid; ///< For targets that need the notion of a current thread.
+
+private:
+ ThreadList ();
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadList_h_
diff --git a/lldb/include/lldb/Target/ThreadPlan.h b/lldb/include/lldb/Target/ThreadPlan.h
new file mode 100644
index 00000000000..96a13264737
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlan.h
@@ -0,0 +1,358 @@
+//===-- 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"
+
+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.
+//
+//
+// DEPRECATED: This ended up causing a real hassle, too many cases where the immediate plan
+// got stranded. So the better way to do this is to post any plans you need to do right before
+// running in the PrepareToResume method.
+//f
+// Immediate Plans:
+//
+// One other complexity of the plan stack is that sometimes you need to do a piece of work immediately
+// on resume, regardless of what other plans have been pushed on the stack while the process has
+// been stopped. The classic example is stepping over a breakpoint. To that end the plan stack is
+// actually two stacks, an "immediate" plan stack and the normal plan stack. A plan can indicate that it
+// should go on the immediate plan stack by returning "true" from the IsImmediate method.
+//
+// END DEPRECATED...
+//
+// 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.
+//
+// When the plan is moved from the plan stack to the completed plan stack its DidPop method is called. You should
+// undo anything that affects target state in this method so the target state is clear for new plans.
+// But be sure to leave whatever state might be needed to correctly fill the StopInfo.
+//
+// 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.
+// 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.
+// 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.
+// In the normal case, this will just 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.
+//
+// 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.
+//
+// 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;
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ThreadPlan (const char *name,
+ Thread &thread,
+ lldb::Vote stop_vote,
+ lldb::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;
+
+ //------------------------------------------------------------------
+ /// Returns the Thread that is using this thread plan.
+ ///
+ /// @return
+ /// A pointer to the thread plan's owning thread.
+ //------------------------------------------------------------------
+ Thread &
+ GetThread();
+
+ const Thread &
+ GetThread() const;
+
+ //------------------------------------------------------------------
+ /// 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 needs to be executed immediatly on resume.
+ ///
+ /// @return
+ /// \b true if the plan is immediate, \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ IsImmediate() const
+ {
+ return false;
+ }
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @return
+ /// \b true if the plan should be queued, \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ ValidatePlan (Stream *error) = 0;
+
+ virtual bool
+ PlanExplainsStop () = 0;
+
+
+ virtual lldb::StateType
+ RunState () = 0;
+
+ virtual bool
+ ShouldStop (Event *event_ptr) = 0;
+
+ // 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 lldb::Vote
+ ShouldReportStop (Event *event_ptr);
+
+ virtual lldb::Vote
+ ShouldReportRun (Event *event_ptr);
+
+ virtual bool
+ StopOthers ();
+
+ virtual bool
+ WillResume (lldb::StateType resume_state, bool current_plan);
+
+ virtual bool
+ WillStop () = 0;
+
+ virtual bool
+ IsMasterPlan()
+ {
+ return false;
+ }
+
+ 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 ();
+
+ bool
+ GetPrivate ();
+
+ void
+ SetPrivate (bool 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);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from ThreadPlan can see and modify these
+ //------------------------------------------------------------------
+
+ bool
+ IsPlanComplete();
+
+ void
+ SetPlanComplete ();
+
+ // 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 ();
+
+ Thread &m_thread;
+ lldb::Vote m_stop_vote;
+ lldb::Vote m_run_vote;
+
+private:
+ //------------------------------------------------------------------
+ // For ThreadPlan only
+ //------------------------------------------------------------------
+ static lldb::user_id_t GetNextID ();
+
+ std::string m_name;
+ Mutex m_plan_complete_mutex;
+ bool m_plan_complete;
+ bool m_plan_private;
+ bool m_okay_to_discard;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(ThreadPlan);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlan_h_
diff --git a/lldb/include/lldb/Target/ThreadPlanBase.h b/lldb/include/lldb/Target/ThreadPlanBase.h
new file mode 100644
index 00000000000..6a0dbfc405a
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlanBase.h
@@ -0,0 +1,66 @@
+//===-- 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/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
+{
+public:
+ virtual ~ThreadPlanBase ();
+
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
+ virtual bool ValidatePlan (Stream *error);
+ virtual bool PlanExplainsStop ();
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType RunState ();
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+
+ virtual bool IsMasterPlan()
+ {
+ return true;
+ }
+
+ virtual bool OkayToDiscard()
+ {
+ return false;
+ }
+
+protected:
+ ThreadPlanBase (Thread &thread);
+
+private:
+ friend ThreadPlan *
+ Thread::QueueFundamentalPlan(bool abort_other_plans);
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanBase);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanFundamental_h_
diff --git a/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/lldb/include/lldb/Target/ThreadPlanCallFunction.h
new file mode 100644
index 00000000000..53b2a87afa7
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlanCallFunction.h
@@ -0,0 +1,96 @@
+//===-- 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
+{
+public:
+ ThreadPlanCallFunction (Thread &thread,
+ Address &function,
+ lldb::addr_t arg,
+ bool stop_other_threads,
+ bool discard_on_error = true);
+
+ ThreadPlanCallFunction (Thread &thread,
+ Address &function,
+ ValueList &args,
+ bool stop_other_threads,
+ bool discard_on_error = true);
+
+ virtual
+ ~ThreadPlanCallFunction ();
+
+ virtual void
+ GetDescription (Stream *s, lldb::DescriptionLevel level);
+
+ virtual bool
+ ValidatePlan (Stream *error);
+
+ virtual bool
+ PlanExplainsStop ();
+
+ virtual bool
+ ShouldStop (Event *event_ptr);
+
+ virtual bool
+ StopOthers ();
+
+ virtual void
+ SetStopOthers (bool new_value);
+
+ virtual lldb::StateType
+ RunState ();
+
+ virtual void
+ DidPush ();
+
+ virtual bool
+ WillStop ();
+
+ virtual bool
+ MischiefManaged ();
+
+ virtual bool
+ IsMasterPlan()
+ {
+ return true;
+ }
+
+protected:
+private:
+ bool m_use_abi;
+ bool m_valid;
+ bool m_stop_other_threads;
+ Address m_function_addr;
+ Address m_start_addr;
+ lldb::addr_t m_arg_addr;
+ ValueList *m_args;
+ Process &m_process;
+ Thread &m_thread;
+ Thread::RegisterCheckpoint m_register_backup;
+ lldb::ThreadPlanSP m_subplan_sp;
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallFunction);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanCallFunction_h_
diff --git a/lldb/include/lldb/Target/ThreadPlanContinue.h b/lldb/include/lldb/Target/ThreadPlanContinue.h
new file mode 100644
index 00000000000..bd50c737fd7
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlanContinue.h
@@ -0,0 +1,60 @@
+//===-- ThreadPlanContinue.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ThreadPlanContinue_h_
+#define liblldb_ThreadPlanContinue_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ThreadPlan.h"
+
+namespace lldb_private {
+
+class ThreadPlanContinue : public ThreadPlan
+{
+public:
+ ThreadPlanContinue (Thread &thread,
+ bool stop_others,
+ lldb::Vote stop_vote,
+ lldb::Vote run_vote,
+ bool immediate = false);
+ virtual ~ThreadPlanContinue ();
+
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
+
+ virtual bool ValidatePlan (Stream *error);
+
+ virtual bool PlanExplainsStop ();
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType RunState ();
+ virtual bool IsImmediate () const;
+ virtual bool WillResume (lldb::StateType resume_state, bool current_plan);
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+
+protected:
+ bool InRange();
+private:
+ bool m_stop_others;
+ bool m_did_run;
+ bool m_immediate;
+ // Need an appropriate marker for the current stack so we can tell step out
+ // from step in.
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanContinue);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanContinue_h_
diff --git a/lldb/include/lldb/Target/ThreadPlanRunToAddress.h b/lldb/include/lldb/Target/ThreadPlanRunToAddress.h
new file mode 100644
index 00000000000..3b591ea3324
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlanRunToAddress.h
@@ -0,0 +1,78 @@
+//===-- 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
+// 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);
+
+ virtual
+ ~ThreadPlanRunToAddress ();
+
+ virtual void
+ GetDescription (Stream *s, lldb::DescriptionLevel level);
+
+ virtual bool
+ ValidatePlan (Stream *error);
+
+ virtual bool
+ PlanExplainsStop ();
+
+ virtual bool
+ ShouldStop (Event *event_ptr);
+
+ virtual bool
+ StopOthers ();
+
+ virtual void
+ SetStopOthers (bool new_value);
+
+ virtual lldb::StateType
+ RunState ();
+
+ virtual bool
+ WillStop ();
+
+ virtual bool
+ MischiefManaged ();
+
+protected:
+ void SetInitialBreakpoint();
+ bool AtOurAddress();
+private:
+ bool m_stop_others;
+ lldb::addr_t m_address; // This is the address we are going to run to.
+ // TODO: Would it be useful to have multiple addresses?
+ lldb::user_id_t m_break_id; // 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/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h
new file mode 100644
index 00000000000..66270dfa5a3
--- /dev/null
+++ b/lldb/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);
+
+ ThreadPlan *
+ 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/lldb/include/lldb/Target/ThreadPlanStepInRange.h b/lldb/include/lldb/Target/ThreadPlanStepInRange.h
new file mode 100644
index 00000000000..2e0b4cb8385
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlanStepInRange.h
@@ -0,0 +1,76 @@
+//===-- 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:
+ virtual
+ ~ThreadPlanStepInRange ();
+
+ virtual void
+ GetDescription (Stream *s, lldb::DescriptionLevel level);
+
+ virtual bool
+ ShouldStop (Event *event_ptr);
+
+ static ThreadPlan *
+ DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton);
+
+ static void
+ SetDefaultFlagValue (uint32_t new_value);
+
+protected:
+
+ ThreadPlanStepInRange (Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others);
+
+ virtual void
+ SetFlagsToDefault ();
+
+private:
+
+ friend ThreadPlan *
+ Thread::QueueThreadPlanForStepRange (bool abort_other_plans,
+ lldb::StepType type,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others);
+
+
+ // Need an appropriate marker for the current stack so we can tell step out
+ // from step in.
+
+ static uint32_t s_default_flag_values;
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepInRange);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepInRange_h_
diff --git a/lldb/include/lldb/Target/ThreadPlanStepInstruction.h b/lldb/include/lldb/Target/ThreadPlanStepInstruction.h
new file mode 100644
index 00000000000..2157e84d8e9
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlanStepInstruction.h
@@ -0,0 +1,61 @@
+//===-- 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 PlanExplainsStop ();
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType RunState ();
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+
+protected:
+ ThreadPlanStepInstruction (Thread &thread,
+ bool step_over,
+ bool stop_others,
+ lldb::Vote stop_vote,
+ lldb::Vote run_vote);
+
+private:
+ friend ThreadPlan *
+ 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;
+ // This is used only for the step over case.
+ uint64_t m_stack_depth;
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepInstruction);
+
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepInstruction_h_
diff --git a/lldb/include/lldb/Target/ThreadPlanStepOut.h b/lldb/include/lldb/Target/ThreadPlanStepOut.h
new file mode 100644
index 00000000000..fd74e7199c3
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlanStepOut.h
@@ -0,0 +1,72 @@
+//===-- 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:
+ virtual ~ThreadPlanStepOut ();
+
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
+ virtual bool ValidatePlan (Stream *error);
+ virtual bool PlanExplainsStop ();
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType RunState ();
+ virtual bool WillResume (lldb::StateType resume_state, bool current_plan);
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+
+protected:
+ ThreadPlanStepOut (Thread &thread,
+ SymbolContext *addr_context,
+ bool first_insn,
+ bool stop_others,
+ lldb::Vote stop_vote,
+ lldb::Vote run_vote);
+
+private:
+ SymbolContext *m_step_from_context;
+ lldb::addr_t m_step_from_insn;
+ uint64_t m_stack_depth;
+ lldb::break_id_t m_return_bp_id;
+ lldb::addr_t m_return_addr;
+ bool m_first_insn;
+ bool m_stop_others;
+
+ friend ThreadPlan *
+ Thread::QueueThreadPlanForStepOut (bool abort_other_plans,
+ SymbolContext *addr_context,
+ bool first_insn,
+ bool stop_others,
+ lldb::Vote stop_vote,
+ lldb::Vote run_vote);
+
+ // Need an appropriate marker for the current stack so we can tell step out
+ // from step in.
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepOut);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepOut_h_
diff --git a/lldb/include/lldb/Target/ThreadPlanStepOverBreakpoint.h b/lldb/include/lldb/Target/ThreadPlanStepOverBreakpoint.h
new file mode 100644
index 00000000000..14ba453ffd9
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlanStepOverBreakpoint.h
@@ -0,0 +1,55 @@
+//===-- 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 PlanExplainsStop ();
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType RunState ();
+ virtual bool IsImmediate () const
+ {
+ return false;
+ }
+ virtual bool WillResume (lldb::StateType resume_state, bool current_plan);
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+
+protected:
+
+private:
+
+ lldb::addr_t m_breakpoint_addr;
+ lldb::user_id_t m_breakpoint_site_id;
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepOverBreakpoint);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepOverBreakpoint_h_
diff --git a/lldb/include/lldb/Target/ThreadPlanStepOverRange.h b/lldb/include/lldb/Target/ThreadPlanStepOverRange.h
new file mode 100644
index 00000000000..9ecde535eb9
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlanStepOverRange.h
@@ -0,0 +1,56 @@
+//===-- 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:
+ virtual ~ThreadPlanStepOverRange ();
+
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool
+ IsMasterPlan()
+ {
+ return true;
+ }
+
+protected:
+
+ ThreadPlanStepOverRange (Thread &thread, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_others, bool okay_to_discard = false);
+
+private:
+
+ friend ThreadPlan *
+ Thread::QueueThreadPlanForStepRange (bool abort_other_plans,
+ lldb::StepType type,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others);
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepOverRange);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepOverRange_h_
diff --git a/lldb/include/lldb/Target/ThreadPlanStepRange.h b/lldb/include/lldb/Target/ThreadPlanStepRange.h
new file mode 100644
index 00000000000..dfdd2e20e50
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlanStepRange.h
@@ -0,0 +1,74 @@
+//===-- 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:
+ virtual ~ThreadPlanStepRange ();
+
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level) = 0;
+ virtual bool ValidatePlan (Stream *error);
+ virtual bool PlanExplainsStop ();
+ virtual bool ShouldStop (Event *event_ptr) = 0;
+ virtual lldb::Vote ShouldReportStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType RunState ();
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+
+protected:
+
+ ThreadPlanStepRange (const char *name,
+ Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others);
+
+ bool InRange();
+ bool FrameIsYounger();
+ bool FrameIsOlder();
+ bool InSymbol();
+
+ SymbolContext m_addr_context;
+ AddressRange m_address_range;
+ lldb::RunMode m_stop_others;
+ uint32_t m_stack_depth;
+ 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.
+
+private:
+
+ // friend ThreadPlan *
+ // Thread::QueueThreadPlanForStepRange (bool abort_other_plans, StepType type, const AddressRange &range, SymbolContext *addr_context, bool stop_others);
+
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepRange);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepRange_h_
diff --git a/lldb/include/lldb/Target/ThreadPlanStepThrough.h b/lldb/include/lldb/Target/ThreadPlanStepThrough.h
new file mode 100644
index 00000000000..4763da719b8
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlanStepThrough.h
@@ -0,0 +1,58 @@
+//===-- 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 PlanExplainsStop ();
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType RunState ();
+ virtual bool WillResume (lldb::StateType resume_state, bool current_plan);
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+
+protected:
+ ThreadPlanStepThrough (Thread &thread,
+ bool stop_others);
+
+ bool
+ HappyToStopHere ();
+
+private:
+ friend ThreadPlan *
+ Thread::QueueThreadPlanForStepThrough (bool abort_other_plans,
+ bool stop_others);
+
+ lldb::addr_t m_start_address;
+ bool m_stop_others;
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepThrough);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepThrough_h_
diff --git a/lldb/include/lldb/Target/ThreadPlanStepUntil.h b/lldb/include/lldb/Target/ThreadPlanStepUntil.h
new file mode 100644
index 00000000000..504fd2f8dfa
--- /dev/null
+++ b/lldb/include/lldb/Target/ThreadPlanStepUntil.h
@@ -0,0 +1,83 @@
+//===-- 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 PlanExplainsStop ();
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType RunState ();
+ virtual bool WillResume (lldb::StateType resume_state, bool current_plan);
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+
+ virtual bool
+ IsMasterPlan()
+ {
+ return true;
+ }
+
+protected:
+ ThreadPlanStepUntil (Thread &thread,
+ lldb::addr_t *address_list,
+ size_t num_addresses,
+ bool stop_others);
+ void AnalyzeStop(void);
+
+private:
+
+ uint64_t m_stack_depth;
+ 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 ThreadPlan *
+ Thread::QueueThreadPlanForStepUntil (bool abort_other_plans,
+ lldb::addr_t *address_list,
+ size_t num_addresses,
+ bool stop_others);
+
+ // 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/lldb/include/lldb/Target/UnixSignals.h b/lldb/include/lldb/Target/UnixSignals.h
new file mode 100644
index 00000000000..c83a5a4d8ad
--- /dev/null
+++ b/lldb/include/lldb/Target/UnixSignals.h
@@ -0,0 +1,168 @@
+//===-- 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,
+ bool default_suppress,
+ bool default_stop,
+ bool default_notify);
+
+ void
+ RemoveSignal (int signo);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from UnixSignals can see and modify these
+ //------------------------------------------------------------------
+
+ struct Signal
+ {
+ typedef enum
+ {
+ eCondSuppress = 0,
+ eCondStop = 1,
+ eCondNotify
+ } Condition;
+
+ ConstString m_name;
+ bool m_conditions[3];
+
+ Signal (const char *name,
+ bool default_suppress,
+ bool default_stop,
+ bool default_notify);
+
+ ~Signal () {}
+ };
+
+ bool
+ GetCondition (int signo,
+ Signal::Condition cond_pos) const;
+ bool
+ SetCondition (int signo,
+ Signal::Condition cond_pos,
+ bool value);
+
+ bool
+ SetCondition (const char *signal_name,
+ Signal::Condition cond_pos,
+ bool value);
+
+ Signal *
+ GetSignalByName (const char *name,
+ int32_t &signo);
+
+ const Signal *
+ GetSignalByName (const char *name,
+ int32_t &signo) const;
+
+ void
+ Reset ();
+
+private:
+ //------------------------------------------------------------------
+ // For UnixSignals only
+ //------------------------------------------------------------------
+ typedef std::map <int32_t, Signal> collection;
+
+ collection m_signals;
+
+ DISALLOW_COPY_AND_ASSIGN (UnixSignals);
+};
+
+} // Namespace lldb
+#endif // lldb_UnixSignals_h_
diff --git a/lldb/include/lldb/Target/Unwind.h b/lldb/include/lldb/Target/Unwind.h
new file mode 100644
index 00000000000..f863add40dc
--- /dev/null
+++ b/lldb/include/lldb/Target/Unwind.h
@@ -0,0 +1,69 @@
+//===-- 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"
+
+namespace lldb_private {
+
+class Unwind
+{
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from Unwind can see and modify these
+ //------------------------------------------------------------------
+ Unwind(Thread &thread) :
+ m_thread (thread)
+ {
+ }
+
+public:
+ virtual
+ ~Unwind()
+ {
+ }
+
+ virtual void
+ Clear() = 0;
+
+ virtual uint32_t
+ GetFrameCount() = 0;
+
+ virtual bool
+ GetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& pc) = 0;
+
+ virtual RegisterContext *
+ CreateRegisterContextForFrame (StackFrame *frame) = 0;
+
+ Thread &
+ GetThread()
+ {
+ return m_thread;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from Unwind can see and modify these
+ //------------------------------------------------------------------
+ Thread &m_thread;
+private:
+ DISALLOW_COPY_AND_ASSIGN (Unwind);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Unwind_h_
diff --git a/lldb/include/lldb/lldb-defines.h b/lldb/include/lldb/lldb-defines.h
new file mode 100644
index 00000000000..89d17af4ddf
--- /dev/null
+++ b/lldb/include/lldb/lldb-defines.h
@@ -0,0 +1,88 @@
+//===-- 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_defines_h_
+#define 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 defines
+//----------------------------------------------------------------------
+#define LLDB_GENERIC_ERROR ((uint32_t)UINT32_MAX)
+
+//----------------------------------------------------------------------
+// Breakpoints
+//----------------------------------------------------------------------
+#define LLDB_INVALID_BREAK_ID ((lldb::break_id_t)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 ((lldb::user_id_t)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)
+
+//----------------------------------------------------------------------
+// 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
+
+//----------------------------------------------------------------------
+/// Invalid value definitions
+//----------------------------------------------------------------------
+#define LLDB_INVALID_ADDRESS (~((lldb::addr_t)0))
+#define LLDB_INVALID_INDEX32 ((uint32_t)UINT32_MAX)
+#define LLDB_INVALID_REGNUM ((uint32_t)UINT32_MAX)
+#define LLDB_INVALID_UID ((lldb::user_id_t)UINT32_MAX)
+#define LLDB_INVALID_PROCESS_ID ((lldb::pid_t)0)
+#define LLDB_INVALID_THREAD_ID ((lldb::tid_t)0)
+#define LLDB_INVALID_FRAME_ID ((uint32_t) UINT32_MAX)
+#define LLDB_INVALID_SIGNAL_NUMBER ((int32_t) INT32_MAX)
+
+//----------------------------------------------------------------------
+/// 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)
+
+
+
+#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_defines_h_
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
new file mode 100644
index 00000000000..8ad33500ee4
--- /dev/null
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -0,0 +1,358 @@
+//===-- 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_enumerations_h_
+#define LLDB_enumerations_h_
+
+namespace lldb {
+
+//----------------------------------------------------------------------
+// Process and Thread States
+//----------------------------------------------------------------------
+typedef enum StateType
+{
+ eStateInvalid = 0,
+ eStateUnloaded,
+ eStateAttaching,
+ eStateLaunching,
+ eStateStopped,
+ eStateRunning,
+ eStateStepping,
+ eStateCrashed,
+ eStateDetached,
+ eStateExited,
+ eStateSuspended
+} StateType;
+
+//----------------------------------------------------------------------
+// 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;
+
+//----------------------------------------------------------------------
+// Thread Run Modes
+//----------------------------------------------------------------------
+typedef enum RunMode {
+ eOnlyThisThread,
+ eAllThreads,
+ eOnlyDuringStepping
+} RunMode;
+
+//----------------------------------------------------------------------
+// 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;
+
+//----------------------------------------------------------------------
+// Byte ordering definitions
+//----------------------------------------------------------------------
+typedef enum ByteOrder
+{
+ eByteOrderInvalid = 0,
+ eByteOrderLittle = 1234,
+ eByteOrderBig = 4321,
+ eByteOrderPDP = 3412,
+#if defined (__LITTLE_ENDIAN__)
+ eByteOrderHost = eByteOrderLittle
+#elif defined (__BIG_ENDIAN__)
+ eByteOrderHost = eByteOrderBig
+#elif defined (__PDP_ENDIAN__)
+ eByteOrderHost = eByteOrderPDP
+#else
+#error unable to detect endianness
+#endif
+} 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,
+ eFormatCString, // NULL terminated C strings
+ eFormatDecimal,
+ eFormatEnum,
+ eFormatHex,
+ eFormatFloat,
+ eFormatOctal,
+ eFormatUnicode16,
+ eFormatUnicode32,
+ eFormatUnsigned,
+ eFormatPointer,
+ eFormatVectorOfChar,
+ eFormatVectorOfSInt8,
+ eFormatVectorOfUInt8,
+ eFormatVectorOfSInt16,
+ eFormatVectorOfUInt16,
+ eFormatVectorOfSInt32,
+ eFormatVectorOfUInt32,
+ eFormatVectorOfSInt64,
+ eFormatVectorOfUInt64,
+ eFormatVectorOfFloat32,
+ eFormatVectorOfFloat64,
+ eFormatVectorOfUInt128,
+
+} Format;
+
+//----------------------------------------------------------------------
+// Description levels for "void GetDescription(Stream *, DescriptionLevel)" calls
+//----------------------------------------------------------------------
+typedef enum DescriptionLevel
+{
+ eDescriptionLevelBrief = 0,
+ eDescriptionLevelFull,
+ eDescriptionLevelVerbose,
+ kNumDescriptionLevels
+} DescriptionLevel;
+
+//----------------------------------------------------------------------
+// Script interpreter types
+//----------------------------------------------------------------------
+typedef enum ScriptLanguage
+{
+ eScriptLanguageNone,
+ eScriptLanguagePython,
+ eScriptLanguageDefault = eScriptLanguagePython
+} ScriptLanguage;
+
+//----------------------------------------------------------------------
+// Register numbering types
+//----------------------------------------------------------------------
+typedef enum RegisterKind
+{
+ eRegisterKindGCC = 0,
+ eRegisterKindDWARF,
+ eRegisterKindGeneric,
+ eRegisterKindGDB,
+ kNumRegisterKinds
+} RegisterKind;
+
+//----------------------------------------------------------------------
+// Thread stop reasons
+//----------------------------------------------------------------------
+typedef enum StopReason
+{
+ eStopReasonInvalid = 0,
+ eStopReasonNone,
+ eStopReasonTrace,
+ eStopReasonBreakpoint,
+ eStopReasonWatchpoint,
+ eStopReasonSignal,
+ eStopReasonException,
+ eStopReasonPlanComplete
+} StopReason;
+
+//----------------------------------------------------------------------
+// Votes - Need a tri-state, yes, no, no opinion...
+//----------------------------------------------------------------------
+typedef enum Vote
+{
+ eVoteNo = -1,
+ eVoteNoOpinion = 0,
+ eVoteYes = 1,
+} Vote;
+
+//----------------------------------------------------------------------
+// Symbol types
+//----------------------------------------------------------------------
+typedef enum SymbolType
+{
+ eSymbolTypeAny = 0,
+ eSymbolTypeInvalid = 0,
+ eSymbolTypeAbsolute,
+ eSymbolTypeExtern,
+ eSymbolTypeCode,
+ eSymbolTypeData,
+ eSymbolTypeTrampoline,
+ eSymbolTypeRuntime,
+ eSymbolTypeException,
+ eSymbolTypeSourceFile,
+ eSymbolTypeHeaderFile,
+ eSymbolTypeObjectFile,
+ eSymbolTypeFunction,
+ eSymbolTypeFunctionEnd,
+ eSymbolTypeCommonBlock,
+ eSymbolTypeBlock,
+ eSymbolTypeStatic,
+ eSymbolTypeGlobal,
+ 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
+} SymbolType;
+
+
+//----------------------------------------------------------------------
+// Command Return Status Types
+//----------------------------------------------------------------------
+typedef enum ReturnStatus
+{
+ eReturnStatusInvalid,
+ eReturnStatusSuccessFinishNoResult,
+ eReturnStatusSuccessFinishResult,
+ eReturnStatusSuccessContinuingNoResult,
+ eReturnStatusSuccessContinuingResult,
+ eReturnStatusStarted,
+ eReturnStatusFailed,
+ eReturnStatusQuit
+} ReturnStatus;
+
+
+//----------------------------------------------------------------------
+// Connection Status Types
+//----------------------------------------------------------------------
+typedef enum ConnectionStatus
+{
+ eConnectionStatusSuccess, // Success
+ 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
+} 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 = (1 << 0), ///< Set when \a target is requested from a query, or was located in query results
+ eSymbolContextModule = (1 << 1), ///< Set when \a module is requested from a query, or was located in query results
+ eSymbolContextCompUnit = (1 << 2), ///< Set when \a comp_unit is requested from a query, or was located in query results
+ eSymbolContextFunction = (1 << 3), ///< Set when \a function is requested from a query, or was located in query results
+ eSymbolContextBlock = (1 << 4), ///< Set when the deepest \a block is requested from a query, or was located in query results
+ eSymbolContextLineEntry = (1 << 5), ///< Set when \a line_entry is requested from a query, or was located in query results
+ eSymbolContextSymbol = (1 << 6), ///< Set when \a symbol is requested from a query, or was located in query results
+ eSymbolContextEverything = ((eSymbolContextSymbol << 1) - 1) ///< Indicates to try and lookup everything up during a query.
+} SymbolContextItem;
+
+typedef enum Permissions
+{
+ ePermissionsWritable = (1 << 0),
+ ePermissionsReadable = (1 << 1),
+ ePermissionsExecutable = (1 << 2)
+};
+
+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
+ eSectionTypeOther
+
+} SectionType;
+
+
+typedef enum InputReaderAction
+{
+ eInputReaderActivate, // reader is newly pushed onto the reader stack
+ 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)
+ eInputReaderDone, // reader was just popped off the stack and is done
+} InputReaderAction;
+
+} // namespace lldb
+
+
+#endif // LLDB_enumerations_h_
diff --git a/lldb/include/lldb/lldb-forward-rtti.h b/lldb/include/lldb/lldb-forward-rtti.h
new file mode 100644
index 00000000000..163a319c901
--- /dev/null
+++ b/lldb/include/lldb/lldb-forward-rtti.h
@@ -0,0 +1,76 @@
+//===-- lldb-forward-rtti.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_forward_rtti_h_
+#define LLDB_forward_rtti_h_
+
+#if defined(__cplusplus)
+
+#ifndef NO_RTTI
+//----------------------------------------------------------------------
+// And source files that may not have RTTI enabled during their
+// compilation will want to do a "#define NO_RTTI" before including the
+// lldb-include.h file.
+//----------------------------------------------------------------------
+
+#include <LLDB/lldb-types.h>
+#include <LLDB/lldb-forward.h>
+
+//----------------------------------------------------------------------
+// lldb forward declarations
+//----------------------------------------------------------------------
+namespace lldb {
+
+ typedef SharedPtr<lldb_private::ABI>::Type ABISP;
+ typedef SharedPtr<lldb_private::AddressResolver>::Type AddressResolverSP;
+ typedef SharedPtr<lldb_private::Baton>::Type BatonSP;
+ typedef SharedPtr<lldb_private::Block>::Type BlockSP;
+ typedef SharedPtr<lldb_private::Breakpoint>::Type BreakpointSP;
+ typedef SharedPtr<lldb_private::BreakpointSite>::Type BreakpointSiteSP;
+ typedef SharedPtr<lldb_private::BreakpointLocation>::Type BreakpointLocationSP;
+ typedef SharedPtr<lldb_private::BreakpointResolver>::Type BreakpointResolverSP;
+ typedef SharedPtr<lldb_private::Broadcaster>::Type BroadcasterSP;
+ typedef SharedPtr<lldb_private::CommandObject>::Type CommandObjectSP;
+ typedef SharedPtr<lldb_private::Communication>::Type CommunicationSP;
+ typedef SharedPtr<lldb_private::CompileUnit>::Type CompUnitSP;
+ typedef SharedPtr<lldb_private::DataBuffer>::Type DataBufferSP;
+ typedef SharedPtr<lldb_private::DynamicLoader>::Type DynamicLoaderSP;
+ typedef SharedPtr<lldb_private::Event>::Type EventSP;
+ typedef SharedPtr<lldb_private::Function>::Type FunctionSP;
+ typedef SharedPtr<lldb_private::InlineFunctionInfo>::Type InlineFunctionInfoSP;
+ typedef SharedPtr<lldb_private::InputReader>::Type InputReaderSP;
+ typedef SharedPtr<lldb_private::LineTable>::Type LineTableSP;
+ typedef SharedPtr<lldb_private::Listener>::Type ListenerSP;
+ typedef SharedPtr<lldb_private::Log>::Type LogSP;
+ typedef SharedPtr<lldb_private::LogChannel>::Type LogChannelSP;
+ typedef SharedPtr<lldb_private::Module>::Type ModuleSP;
+ typedef SharedPtr<lldb_private::Process>::Type ProcessSP;
+ typedef SharedPtr<lldb_private::RegisterContext>::Type RegisterContextSP;
+ typedef SharedPtr<lldb_private::Section>::Type SectionSP;
+ typedef SharedPtr<lldb_private::SearchFilter>::Type SearchFilterSP;
+ typedef SharedPtr<lldb_private::StackFrame>::Type StackFrameSP;
+ typedef SharedPtr<lldb_private::StateVariable>::Type StateVariableSP;
+ typedef SharedPtr<lldb_private::StoppointLocation>::Type StoppointLocationSP;
+ typedef SharedPtr<lldb_private::Stream>::Type StreamSP;
+ typedef SharedPtr<lldb_private::SymbolFile>::Type SymbolFileSP;
+ typedef SharedPtr<lldb_private::Target>::Type TargetSP;
+ typedef SharedPtr<lldb_private::Thread>::Type ThreadSP;
+ typedef SharedPtr<lldb_private::ThreadPlan>::Type ThreadPlanSP;
+ typedef SharedPtr<lldb_private::Type>::Type TypeSP;
+ typedef SharedPtr<lldb_private::ValueObject>::Type ValueObjectSP;
+ typedef SharedPtr<lldb_private::Variable>::Type VariableSP;
+ typedef SharedPtr<lldb_private::VariableList>::Type VariableListSP;
+
+} // namespace lldb
+
+#endif // #ifndef NO_RTTI
+
+#endif // #if defined(__cplusplus)
+
+#endif // LLDB_forward_rtti_h_
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
new file mode 100644
index 00000000000..9e69ca09f52
--- /dev/null
+++ b/lldb/include/lldb/lldb-forward.h
@@ -0,0 +1,149 @@
+//===-- 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_forward_h_
+#define LLDB_forward_h_
+
+#if defined(__cplusplus)
+
+//----------------------------------------------------------------------
+// lldb forward declarations
+//----------------------------------------------------------------------
+namespace lldb_private {
+
+class ABI;
+class Address;
+class AddressRange;
+class AddressResolver;
+class ArchSpec;
+class Args;
+class Baton;
+class Block;
+class BlockList;
+class Breakpoint;
+class BreakpointID;
+class BreakpointIDList;
+class BreakpointSite;
+class BreakpointSiteList;
+class BreakpointList;
+class BreakpointLocation;
+class BreakpointLocationCollection;
+class BreakpointLocationList;
+class BreakpointOptions;
+class BreakpointResolver;
+class Broadcaster;
+class ClangASTContext;
+class ClangExpression;
+class ClangExpressionDeclMap;
+class ClangExpressionVariableList;
+class CommandContext;
+class CommandInterpreter;
+class CommandObject;
+class CommandReturnObject;
+class Communication;
+class Condition;
+class CompileUnit;
+class Connection;
+class ConnectionFileDescriptor;
+class ConstString;
+class DWARFCallFrameInfo;
+class DWARFExpression;
+class DataBuffer;
+class DataExtractor;
+class Debugger;
+class Declaration;
+class Disassembler;
+class DynamicLoader;
+class Error;
+class Event;
+class EventData;
+class ExecutionContext;
+class ExecutionContextScope;
+class FileSpec;
+class FileSpecList;
+class Flags;
+class Function;
+class FunctionInfo;
+class InlineFunctionInfo;
+class InputReader;
+struct LineEntry;
+class LineTable;
+class Listener;
+class Log;
+class LogChannel;
+class Mangled;
+class Module;
+class ModuleList;
+class Mutex;
+class ObjCObjectPrinter;
+class ObjectContainer;
+class ObjectFile;
+class Options;
+class PathMappingList;
+class Process;
+class RegisterContext;
+class RegisterLocation;
+class RegisterLocationList;
+class RegularExpression;
+class Scalar;
+class ScriptInterpreter;
+class ScriptInterpreterPython;
+class SearchFilter;
+class Section;
+class SectionList;
+class SourceManager;
+class StackFrame;
+class StackFrameList;
+class StackID;
+class StateVariable;
+class Stoppoint;
+class StoppointCallbackContext;
+class StoppointLocation;
+class Stream;
+class StreamFile;
+class StreamString;
+class StringList;
+class Symbol;
+class SymbolContext;
+class SymbolContextList;
+class SymbolContextScope;
+class SymbolFile;
+class SymbolVendor;
+class Symtab;
+class Target;
+class TargetList;
+class Thread;
+class ThreadList;
+class ThreadPlan;
+class ThreadPlanContinue;
+class ThreadPlanBase;
+class ThreadPlanStepInstruction;
+class ThreadPlanStepOut;
+class ThreadPlanStepOverBreakpoint;
+class ThreadPlanStepThrough;
+class ThreadPlanStepRange;
+class ThreadPlanRunToAddress;
+class TimeValue;
+class Type;
+class TypeList;
+class Unwind;
+class UUID;
+class VMRange;
+class Value;
+class ValueList;
+class ValueObject;
+class ValueObjectList;
+class Variable;
+class VariableList;
+class WatchpointLocation;
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // LLDB_forward_h_
diff --git a/lldb/include/lldb/lldb-include.h b/lldb/include/lldb/lldb-include.h
new file mode 100644
index 00000000000..de415c48ad9
--- /dev/null
+++ b/lldb/include/lldb/lldb-include.h
@@ -0,0 +1,19 @@
+//===-- 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_include_h_
+#define LLDB_include_h_
+
+#include <LLDB/lldb-defines.h>
+#include <LLDB/lldb-enumerations.h>
+#include <LLDB/lldb-forward.h>
+#include <LLDB/lldb-forward-rtti.h>
+#include <LLDB/lldb-types.h>
+
+#endif // LLDB_include_h_
diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h
new file mode 100644
index 00000000000..3cd8aab476b
--- /dev/null
+++ b/lldb/include/lldb/lldb-private-interfaces.h
@@ -0,0 +1,37 @@
+//===-- 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_interfaces_h_
+#define liblldb_lldb_interfaces_h_
+
+#if defined(__cplusplus)
+#ifndef NO_RTTI
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private
+{
+ typedef ABI* (*ABICreateInstance) (const ConstString &triple);
+ typedef Disassembler* (*DisassemblerCreateInstance) (const ArchSpec &arch);
+ typedef DynamicLoader* (*DynamicLoaderCreateInstance) (Process* process);
+ typedef ObjectContainer* (*ObjectContainerCreateInstance) (Module* module, lldb::DataBufferSP& dataSP, const FileSpec *file, lldb::addr_t offset, lldb::addr_t length);
+ typedef ObjectFile* (*ObjectFileCreateInstance) (Module* module, lldb::DataBufferSP& dataSP, const FileSpec* file, lldb::addr_t offset, lldb::addr_t length);
+ typedef LogChannel* (*LogChannelCreateInstance) ();
+ typedef Process* (*ProcessCreateInstance) (Target &target, Listener &listener);
+ typedef SymbolFile* (*SymbolFileCreateInstance) (ObjectFile* obj_file);
+ typedef SymbolVendor* (*SymbolVendorCreateInstance) (Module *module); // 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, uint32_t type);
+ typedef ThreadPlan * (*ThreadPlanShouldStopHereCallback) (ThreadPlan *current_plan, Flags &flags, void *baton);
+} // namespace lldb_private
+
+#endif // #ifndef NO_RTTI
+#endif // #if defined(__cplusplus)
+
+#endif // liblldb_lldb_interfaces_h_
diff --git a/lldb/include/lldb/lldb-private-log.h b/lldb/include/lldb/lldb-private-log.h
new file mode 100644
index 00000000000..394fe73e269
--- /dev/null
+++ b/lldb/include/lldb/lldb-private-log.h
@@ -0,0 +1,83 @@
+//===-- 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_log_h_
+#define liblldb_lldb_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_SHLIB (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_ALL (UINT32_MAX)
+#define LIBLLDB_LOG_DEFAULT (LIBLLDB_LOG_PROCESS |\
+ LIBLLDB_LOG_THREAD |\
+ LIBLLDB_LOG_SHLIB |\
+ LIBLLDB_LOG_BREAKPOINTS |\
+ LIBLLDB_LOG_WATCHPOINTS |\
+ LIBLLDB_LOG_STEP |\
+ LIBLLDB_LOG_STATE )
+
+namespace lldb_private {
+
+uint32_t
+GetLogMask ();
+
+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 ();
+
+#ifndef NO_RTTI
+
+Log *
+EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, Args &args, Stream *feedback_strm);
+
+#endif
+
+void
+ListLogCategories (Stream *strm);
+
+} // namespace lldb_private
+
+#endif // liblldb_lldb_log_h_
diff --git a/lldb/include/lldb/lldb-private.h b/lldb/include/lldb/lldb-private.h
new file mode 100644
index 00000000000..a67ebf27c14
--- /dev/null
+++ b/lldb/include/lldb/lldb-private.h
@@ -0,0 +1,77 @@
+//===-- 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-include.h"
+#include "lldb/lldb-private-interfaces.h"
+#include "lldb/lldb-private-log.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 ();
+
+// The function below can be moved into lldb::Debugger when/if we get one
+ArchSpec &
+GetDefaultArchitecture ();
+
+} // namespace lldb_private
+
+
+#endif // defined(__cplusplus)
+
+
+#endif // lldb_lldb_private_h_
diff --git a/lldb/include/lldb/lldb-types.h b/lldb/include/lldb/lldb-types.h
new file mode 100644
index 00000000000..c83a3861fd9
--- /dev/null
+++ b/lldb/include/lldb/lldb-types.h
@@ -0,0 +1,168 @@
+//===-- 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_types_h_
+#define LLDB_types_h_
+
+#include <LLDB/lldb-enumerations.h>
+#include <LLDB/lldb-forward.h>
+
+//----------------------------------------------------------------------
+//----------------------------------------------------------------------
+// MACOSX START
+//----------------------------------------------------------------------
+//----------------------------------------------------------------------
+
+#include <assert.h>
+#include <mach/mach_types.h>
+#include <machine/endian.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/syslimits.h>
+#include <unistd.h>
+
+#ifndef NO_RTTI
+
+//----------------------------------------------------------------------
+// And source files that may not have RTTI enabled during their
+// compilation will want to do a "#define NO_RTTI" before including the
+// lldb-include.h file.
+//----------------------------------------------------------------------
+
+#include <tr1/memory> // for std::tr1::shared_ptr
+
+#endif
+
+//----------------------------------------------------------------------
+// All host systems must define:
+// liblldb::condition_t The native condition type (or a substitute class) for conditions on the host system.
+// liblldb::mutex_t The native mutex type for mutex objects on the host system.
+// liblldb::thread_t The native thread type for spawned threads on the system
+// liblldb::thread_arg_t The type of the one any only thread creation argument for the host system
+// liblldb::thread_result_t The return type that gets returned when a thread finishes.
+// liblldb::thread_func_t The function prototype used to spawn a thread on the host system.
+// liblldb::SharedPtr The template that wraps up the host version of a reference counted pointer (like boost::shared_ptr)
+// #define LLDB_INVALID_PROCESS_ID ...
+// #define LLDB_INVALID_THREAD_ID ...
+// #define LLDB_INVALID_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
+
+#ifndef NO_RTTI
+ // The template below can be used in a few useful ways:
+ //
+ // // Make a single shared pointer a class Foo
+ // lldb::SharePtr<Foo>::Type foo_sp;
+ //
+ // // Make a typedef to a Foo shared pointer
+ // typedef lldb::SharePtr<Foo>::Type FooSP;
+ //
+ template<typename _Tp>
+ struct SharedPtr
+ {
+ typedef std::tr1::shared_ptr<_Tp> Type;
+ };
+#endif
+
+} // namespace lldb
+
+#define LLDB_INVALID_HOST_THREAD ((lldb::thread_t)NULL)
+#define LLDB_INVALID_HOST_TIME { 0, 0 }
+
+//----------------------------------------------------------------------
+//----------------------------------------------------------------------
+// MACOSX END
+//----------------------------------------------------------------------
+//----------------------------------------------------------------------
+
+#ifdef SWIG
+#define CONST_CHAR_PTR char *
+#else
+#define CONST_CHAR_PTR const char *
+#endif
+
+namespace lldb {
+ typedef uint64_t addr_t;
+ typedef uint32_t user_id_t;
+ typedef int32_t pid_t;
+ typedef uint32_t tid_t;
+ typedef int32_t break_id_t;
+
+ //----------------------------------------------------------------------
+ // 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_PTR name; // Name of this register, can't be NULL
+ CONST_CHAR_PTR 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 reg; // The native register number for this register
+ uint32_t kinds[kNumRegisterKinds]; // Holds all of the various register numbers for all register kinds
+ } RegisterInfo;
+
+ //----------------------------------------------------------------------
+ // Registers are grouped into register sets
+ //----------------------------------------------------------------------
+ typedef struct
+ {
+ CONST_CHAR_PTR name; // Name of this register set
+ CONST_CHAR_PTR 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
+ {
+ int value;
+ CONST_CHAR_PTR string_value;
+ CONST_CHAR_PTR usage;
+ } OptionEnumValueElement;
+
+ typedef struct
+ {
+ uint32_t usage_level; // Used to mark options that can be used together.
+ bool required; // This option is required (in the current usage level)
+ CONST_CHAR_PTR long_option; // Full name for this option.
+ char 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 completionType; // Cookie the option class can use to do define the argument completion.
+ CONST_CHAR_PTR argument_name; // Text name to be use in usage text to refer to the option's value.
+ CONST_CHAR_PTR usage_text; // Full text explaining what this options does and what (if any) argument to
+ // pass it.
+ } OptionDefinition;
+
+
+ typedef int (*comparison_function)(const void *, const void *);
+}
+
+#undef CONST_CHAR_PTR
+
+#endif // LLDB_types_h_
diff --git a/lldb/lldb.runcontext b/lldb/lldb.runcontext
new file mode 100644
index 00000000000..6a1aaecb51a
--- /dev/null
+++ b/lldb/lldb.runcontext
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RunContext
+ breakPointsEnabled = "YES">
+ <RunPhases>
+ <BuildRunPhase
+ isEnabled = "Yes"
+ name = "Build"
+ buildConfiguration = "Debug">
+ <BuildableOutputReferences>
+ <BuildableOutputReference
+ BuildableOutputIdentifier = "lldb">
+ </BuildableOutputReference>
+ </BuildableOutputReferences>
+ </BuildRunPhase>
+ <ActionRunPhase
+ isEnabled = "Yes"
+ name = "Pre-Launch">
+ <Actions>
+ </Actions>
+ </ActionRunPhase>
+ <LaunchRunPhase
+ isEnabled = "Yes"
+ name = "Launch">
+ <CommandLineArguments>
+ <CommandLineArgument>
+ </CommandLineArgument>
+ </CommandLineArguments>
+ <EnvironmentVariables>
+ </EnvironmentVariables>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ <AdditionalSourceCodeFilesAndDirs>
+ </AdditionalSourceCodeFilesAndDirs>
+ <AdditionalDSYMFilesAndDirs>
+ </AdditionalDSYMFilesAndDirs>
+ </LaunchRunPhase>
+ <ActionRunPhase
+ isEnabled = "Yes"
+ name = "Quit">
+ <Actions>
+ </Actions>
+ </ActionRunPhase>
+ </RunPhases>
+ <BuildableOutputRunnable>
+ <BuildableOutputReference
+ BuildableOutputIdentifier = "lldb">
+ </BuildableOutputReference>
+ </BuildableOutputRunnable>
+</RunContext>
diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj
new file mode 100644
index 00000000000..c5a9c5b4e7f
--- /dev/null
+++ b/lldb/lldb.xcodeproj/project.pbxproj
@@ -0,0 +1,3020 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 260C876A10F538E700BB2B04 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 260C876910F538E700BB2B04 /* Foundation.framework */; };
+ 261744781168585B005ADD65 /* SBType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 261744771168585B005ADD65 /* SBType.cpp */; };
+ 2617447A11685869005ADD65 /* SBType.h in Headers */ = {isa = PBXBuildFile; fileRef = 2617447911685869005ADD65 /* SBType.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 262CFC7711A4510000946C6C /* debugserver in Resources */ = {isa = PBXBuildFile; fileRef = 26CE05A0115C31E50022F371 /* debugserver */; };
+ 265ABF6310F42EE900531910 /* DebugSymbols.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 265ABF6210F42EE900531910 /* DebugSymbols.framework */; };
+ 2668020E115FD12C008E1FE4 /* lldb-defines.h in Headers */ = {isa = PBXBuildFile; fileRef = 26BC7C2510F1B3BC00F91463 /* lldb-defines.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 2668020F115FD12C008E1FE4 /* lldb-enumerations.h in Headers */ = {isa = PBXBuildFile; fileRef = 26BC7C2610F1B3BC00F91463 /* lldb-enumerations.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26680214115FD12C008E1FE4 /* lldb-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 26BC7C2910F1B3BC00F91463 /* lldb-types.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26680219115FD13D008E1FE4 /* SBBreakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AF16A9E11402D69007A7B3F /* SBBreakpoint.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 2668021A115FD13D008E1FE4 /* SBBreakpointLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AF16CC611408686007A7B3F /* SBBreakpointLocation.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 2668021B115FD13D008E1FE4 /* SBBroadcaster.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9830F31125FC5800A56CB0 /* SBBroadcaster.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 2668021C115FD13D008E1FE4 /* SBCommandContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9830F51125FC5800A56CB0 /* SBCommandContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 2668021D115FD13D008E1FE4 /* SBCommandInterpreter.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9830F71125FC5800A56CB0 /* SBCommandInterpreter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 2668021E115FD13D008E1FE4 /* SBCommandReturnObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9830F91125FC5800A56CB0 /* SBCommandReturnObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 2668021F115FD13D008E1FE4 /* SBCommunication.h in Headers */ = {isa = PBXBuildFile; fileRef = 260223E7115F06D500A601A2 /* SBCommunication.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26680220115FD13D008E1FE4 /* SBDebugger.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9830FB1125FC5800A56CB0 /* SBDebugger.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26680221115FD13D008E1FE4 /* SBDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9830FC1125FC5800A56CB0 /* SBDefines.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26680222115FD13D008E1FE4 /* SBError.h in Headers */ = {isa = PBXBuildFile; fileRef = 2682F286115EF3BD00CCFF99 /* SBError.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26680223115FD13D008E1FE4 /* SBEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9830FE1125FC5800A56CB0 /* SBEvent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26680224115FD13D008E1FE4 /* SBFileSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 26022531115F27FA00A601A2 /* SBFileSpec.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26680225115FD13D008E1FE4 /* SBFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A633FE8112DCE3C001A7E43 /* SBFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26680227115FD13D008E1FE4 /* SBListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9831021125FC5800A56CB0 /* SBListener.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 2668022A115FD13D008E1FE4 /* SBProcess.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9831041125FC5800A56CB0 /* SBProcess.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 2668022B115FD13D008E1FE4 /* SBSourceManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9831061125FC5800A56CB0 /* SBSourceManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 2668022C115FD13D008E1FE4 /* SBTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9831081125FC5800A56CB0 /* SBTarget.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 2668022E115FD13D008E1FE4 /* SBThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A98310A1125FC5800A56CB0 /* SBThread.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 2668022F115FD19D008E1FE4 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C39010F3FA26009D5894 /* CoreFoundation.framework */; };
+ 26680230115FD19E008E1FE4 /* DebugSymbols.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 265ABF6210F42EE900531910 /* DebugSymbols.framework */; };
+ 26680231115FD1A0008E1FE4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 260C876910F538E700BB2B04 /* Foundation.framework */; };
+ 26680232115FD1A4008E1FE4 /* libpython2.6.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C32410F3DF23009D5894 /* libpython2.6.dylib */; };
+ 26680233115FD1A7008E1FE4 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C37410F3F61B009D5894 /* libobjc.dylib */; };
+ 26680324116005D9008E1FE4 /* SBThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A9831091125FC5800A56CB0 /* SBThread.cpp */; };
+ 26680326116005DB008E1FE4 /* SBTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A9831071125FC5800A56CB0 /* SBTarget.cpp */; };
+ 26680327116005DC008E1FE4 /* SBSourceManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A9831051125FC5800A56CB0 /* SBSourceManager.cpp */; };
+ 26680328116005DE008E1FE4 /* SBProcess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A9831031125FC5800A56CB0 /* SBProcess.cpp */; };
+ 2668032A116005E0008E1FE4 /* SBListener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A9831011125FC5800A56CB0 /* SBListener.cpp */; };
+ 2668032C116005E2008E1FE4 /* SBFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A633FE7112DCE3C001A7E43 /* SBFrame.cpp */; };
+ 2668032D116005E3008E1FE4 /* SBFileSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26022532115F281400A601A2 /* SBFileSpec.cpp */; };
+ 2668032E116005E5008E1FE4 /* SBEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A9830FD1125FC5800A56CB0 /* SBEvent.cpp */; };
+ 2668032F116005E6008E1FE4 /* SBError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2682F284115EF3A700CCFF99 /* SBError.cpp */; };
+ 26680330116005E7008E1FE4 /* SBDebugger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A9830FA1125FC5800A56CB0 /* SBDebugger.cpp */; };
+ 26680331116005E9008E1FE4 /* SBCommunication.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260223E8115F06E500A601A2 /* SBCommunication.cpp */; };
+ 26680332116005EA008E1FE4 /* SBCommandReturnObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A9830F81125FC5800A56CB0 /* SBCommandReturnObject.cpp */; };
+ 26680333116005EC008E1FE4 /* SBCommandInterpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A9830F61125FC5800A56CB0 /* SBCommandInterpreter.cpp */; };
+ 26680334116005ED008E1FE4 /* SBCommandContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A9830F41125FC5800A56CB0 /* SBCommandContext.cpp */; };
+ 26680335116005EE008E1FE4 /* SBBroadcaster.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A9830F21125FC5800A56CB0 /* SBBroadcaster.cpp */; };
+ 26680336116005EF008E1FE4 /* SBBreakpointLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AF16CC7114086A1007A7B3F /* SBBreakpointLocation.cpp */; };
+ 26680337116005F1008E1FE4 /* SBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AF16A9C11402D5B007A7B3F /* SBBreakpoint.cpp */; };
+ 2668035C11601108008E1FE4 /* LLDB.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26680207115FD0ED008E1FE4 /* LLDB.framework */; };
+ 26B42B1F1187A92B0079C8C8 /* lldb-include.h in Headers */ = {isa = PBXBuildFile; fileRef = 26B42B1E1187A92B0079C8C8 /* lldb-include.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26B42C4D1187ABA50079C8C8 /* LLDB.h in Headers */ = {isa = PBXBuildFile; fileRef = 26B42C4C1187ABA50079C8C8 /* LLDB.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26D5B06511B07550009A862E /* StoppointCallbackContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E0910F1B83100F91463 /* StoppointCallbackContext.cpp */; };
+ 26D5B06611B07550009A862E /* Breakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E0A10F1B83100F91463 /* Breakpoint.cpp */; };
+ 26D5B06711B07550009A862E /* BreakpointID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E0B10F1B83100F91463 /* BreakpointID.cpp */; };
+ 26D5B06811B07550009A862E /* BreakpointIDList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E0C10F1B83100F91463 /* BreakpointIDList.cpp */; };
+ 26D5B06911B07550009A862E /* BreakpointList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E0D10F1B83100F91463 /* BreakpointList.cpp */; };
+ 26D5B06A11B07550009A862E /* BreakpointLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E0E10F1B83100F91463 /* BreakpointLocation.cpp */; };
+ 26D5B06B11B07550009A862E /* BreakpointLocationCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E0F10F1B83100F91463 /* BreakpointLocationCollection.cpp */; };
+ 26D5B06C11B07550009A862E /* BreakpointLocationList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E1010F1B83100F91463 /* BreakpointLocationList.cpp */; };
+ 26D5B06D11B07550009A862E /* BreakpointOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E1110F1B83100F91463 /* BreakpointOptions.cpp */; };
+ 26D5B06E11B07550009A862E /* BreakpointResolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E1210F1B83100F91463 /* BreakpointResolver.cpp */; };
+ 26D5B06F11B07550009A862E /* BreakpointSite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E1310F1B83100F91463 /* BreakpointSite.cpp */; };
+ 26D5B07011B07550009A862E /* BreakpointSiteList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E1410F1B83100F91463 /* BreakpointSiteList.cpp */; };
+ 26D5B07111B07550009A862E /* SearchFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E1510F1B83100F91463 /* SearchFilter.cpp */; };
+ 26D5B07211B07550009A862E /* Stoppoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E1610F1B83100F91463 /* Stoppoint.cpp */; };
+ 26D5B07311B07550009A862E /* StoppointLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E1710F1B83100F91463 /* StoppointLocation.cpp */; };
+ 26D5B07411B07550009A862E /* WatchpointLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E1810F1B83100F91463 /* WatchpointLocation.cpp */; };
+ 26D5B07511B07550009A862E /* CommandObjectAlias.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E2A10F1B84700F91463 /* CommandObjectAlias.cpp */; };
+ 26D5B07611B07550009A862E /* CommandObjectAppend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E2B10F1B84700F91463 /* CommandObjectAppend.cpp */; };
+ 26D5B07711B07550009A862E /* CommandObjectBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E2D10F1B84700F91463 /* CommandObjectBreakpoint.cpp */; };
+ 26D5B07811B07550009A862E /* CommandObjectDelete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E2F10F1B84700F91463 /* CommandObjectDelete.cpp */; };
+ 26D5B07911B07550009A862E /* CommandObjectDisassemble.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3010F1B84700F91463 /* CommandObjectDisassemble.cpp */; };
+ 26D5B07A11B07550009A862E /* CommandObjectExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3110F1B84700F91463 /* CommandObjectExpression.cpp */; };
+ 26D5B07B11B07550009A862E /* CommandObjectFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3210F1B84700F91463 /* CommandObjectFile.cpp */; };
+ 26D5B07C11B07550009A862E /* CommandObjectHelp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3310F1B84700F91463 /* CommandObjectHelp.cpp */; };
+ 26D5B07D11B07550009A862E /* CommandObjectImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3410F1B84700F91463 /* CommandObjectImage.cpp */; };
+ 26D5B07E11B07550009A862E /* CommandObjectInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3510F1B84700F91463 /* CommandObjectInfo.cpp */; };
+ 26D5B07F11B07550009A862E /* CommandObjectMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3610F1B84700F91463 /* CommandObjectMemory.cpp */; };
+ 26D5B08011B07550009A862E /* CommandObjectProcess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3810F1B84700F91463 /* CommandObjectProcess.cpp */; };
+ 26D5B08111B07550009A862E /* CommandObjectQuit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3910F1B84700F91463 /* CommandObjectQuit.cpp */; };
+ 26D5B08211B07550009A862E /* CommandObjectRegister.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3B10F1B84700F91463 /* CommandObjectRegister.cpp */; };
+ 26D5B08311B07550009A862E /* CommandObjectScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3D10F1B84700F91463 /* CommandObjectScript.cpp */; };
+ 26D5B08411B07550009A862E /* CommandObjectSelect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3E10F1B84700F91463 /* CommandObjectSelect.cpp */; };
+ 26D5B08511B07550009A862E /* CommandObjectSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E3F10F1B84700F91463 /* CommandObjectSet.cpp */; };
+ 26D5B08611B07550009A862E /* CommandObjectSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E4010F1B84700F91463 /* CommandObjectSettings.cpp */; };
+ 26D5B08711B07550009A862E /* CommandObjectShow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E4110F1B84700F91463 /* CommandObjectShow.cpp */; };
+ 26D5B08811B07550009A862E /* CommandObjectSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E4210F1B84700F91463 /* CommandObjectSource.cpp */; };
+ 26D5B08911B07550009A862E /* CommandObjectSourceFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E4310F1B84700F91463 /* CommandObjectSourceFile.cpp */; };
+ 26D5B08A11B07550009A862E /* CommandObjectStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E4410F1B84700F91463 /* CommandObjectStatus.cpp */; };
+ 26D5B08B11B07550009A862E /* CommandObjectSyntax.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E4510F1B84700F91463 /* CommandObjectSyntax.cpp */; };
+ 26D5B08C11B07550009A862E /* CommandObjectThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E4610F1B84700F91463 /* CommandObjectThread.cpp */; };
+ 26D5B08D11B07550009A862E /* CommandObjectVariable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E4810F1B84700F91463 /* CommandObjectVariable.cpp */; };
+ 26D5B08E11B07550009A862E /* Address.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E6910F1B85900F91463 /* Address.cpp */; };
+ 26D5B08F11B07550009A862E /* AddressRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E6A10F1B85900F91463 /* AddressRange.cpp */; };
+ 26D5B09011B07550009A862E /* ArchSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E6B10F1B85900F91463 /* ArchSpec.cpp */; };
+ 26D5B09111B07550009A862E /* Args.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E6C10F1B85900F91463 /* Args.cpp */; };
+ 26D5B09211B07550009A862E /* Broadcaster.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E6D10F1B85900F91463 /* Broadcaster.cpp */; };
+ 26D5B09311B07550009A862E /* Communication.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E6E10F1B85900F91463 /* Communication.cpp */; };
+ 26D5B09411B07550009A862E /* Connection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E6F10F1B85900F91463 /* Connection.cpp */; };
+ 26D5B09511B07550009A862E /* ConnectionFileDescriptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7010F1B85900F91463 /* ConnectionFileDescriptor.cpp */; };
+ 26D5B09611B07550009A862E /* DataExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7110F1B85900F91463 /* DataExtractor.cpp */; };
+ 26D5B09711B07550009A862E /* DataBufferHeap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7210F1B85900F91463 /* DataBufferHeap.cpp */; };
+ 26D5B09811B07550009A862E /* DataBufferMemoryMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7310F1B85900F91463 /* DataBufferMemoryMap.cpp */; };
+ 26D5B09911B07550009A862E /* lldb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7410F1B85900F91463 /* lldb.cpp */; };
+ 26D5B09A11B07550009A862E /* lldb-log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7510F1B85900F91463 /* lldb-log.cpp */; };
+ 26D5B09B11B07550009A862E /* Disassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7610F1B85900F91463 /* Disassembler.cpp */; };
+ 26D5B09C11B07550009A862E /* DynamicLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7710F1B85900F91463 /* DynamicLoader.cpp */; };
+ 26D5B09D11B07550009A862E /* Error.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7810F1B85900F91463 /* Error.cpp */; };
+ 26D5B09E11B07550009A862E /* Event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7910F1B85900F91463 /* Event.cpp */; };
+ 26D5B09F11B07550009A862E /* FileSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7A10F1B85900F91463 /* FileSpec.cpp */; };
+ 26D5B0A011B07550009A862E /* FileSpecList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7B10F1B85900F91463 /* FileSpecList.cpp */; };
+ 26D5B0A111B07550009A862E /* Flags.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7C10F1B85900F91463 /* Flags.cpp */; };
+ 26D5B0A211B07550009A862E /* Language.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7D10F1B85900F91463 /* Language.cpp */; };
+ 26D5B0A311B07550009A862E /* Listener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7E10F1B85900F91463 /* Listener.cpp */; };
+ 26D5B0A411B07550009A862E /* Log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7F10F1B85900F91463 /* Log.cpp */; };
+ 26D5B0A511B07550009A862E /* Mangled.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8010F1B85900F91463 /* Mangled.cpp */; };
+ 26D5B0A611B07550009A862E /* Module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8110F1B85900F91463 /* Module.cpp */; };
+ 26D5B0A711B07550009A862E /* ModuleChild.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8210F1B85900F91463 /* ModuleChild.cpp */; };
+ 26D5B0A811B07550009A862E /* ModuleList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8310F1B85900F91463 /* ModuleList.cpp */; };
+ 26D5B0A911B07550009A862E /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8610F1B85900F91463 /* Options.cpp */; };
+ 26D5B0AA11B07550009A862E /* PluginManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8A10F1B85900F91463 /* PluginManager.cpp */; };
+ 26D5B0AB11B07550009A862E /* RegularExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8C10F1B85900F91463 /* RegularExpression.cpp */; };
+ 26D5B0AC11B07550009A862E /* Scalar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8D10F1B85900F91463 /* Scalar.cpp */; };
+ 26D5B0AD11B07550009A862E /* Section.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8E10F1B85900F91463 /* Section.cpp */; };
+ 26D5B0AE11B07550009A862E /* SourceManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8F10F1B85900F91463 /* SourceManager.cpp */; };
+ 26D5B0AF11B07550009A862E /* State.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9010F1B85900F91463 /* State.cpp */; };
+ 26D5B0B011B07550009A862E /* Stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9110F1B85900F91463 /* Stream.cpp */; };
+ 26D5B0B111B07550009A862E /* StreamFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9210F1B85900F91463 /* StreamFile.cpp */; };
+ 26D5B0B211B07550009A862E /* StreamString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9310F1B85900F91463 /* StreamString.cpp */; };
+ 26D5B0B311B07550009A862E /* ConstString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9410F1B85900F91463 /* ConstString.cpp */; };
+ 26D5B0B411B07550009A862E /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9610F1B85900F91463 /* Timer.cpp */; };
+ 26D5B0B511B07550009A862E /* TTYState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9710F1B85900F91463 /* TTYState.cpp */; };
+ 26D5B0B611B07550009A862E /* UserID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9810F1B85900F91463 /* UserID.cpp */; };
+ 26D5B0B711B07550009A862E /* Value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9910F1B85900F91463 /* Value.cpp */; };
+ 26D5B0B811B07550009A862E /* ValueObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9A10F1B85900F91463 /* ValueObject.cpp */; };
+ 26D5B0B911B07550009A862E /* ValueObjectChild.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9B10F1B85900F91463 /* ValueObjectChild.cpp */; };
+ 26D5B0BA11B07550009A862E /* ValueObjectList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9C10F1B85900F91463 /* ValueObjectList.cpp */; };
+ 26D5B0BB11B07550009A862E /* ValueObjectVariable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */; };
+ 26D5B0BC11B07550009A862E /* VMRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9E10F1B85900F91463 /* VMRange.cpp */; };
+ 26D5B0BD11B07550009A862E /* ClangExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7ED510F1B86700F91463 /* ClangExpression.cpp */; };
+ 26D5B0BE11B07550009A862E /* ClangExpressionVariable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7ED610F1B86700F91463 /* ClangExpressionVariable.cpp */; };
+ 26D5B0BF11B07550009A862E /* ClangStmtVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7ED710F1B86700F91463 /* ClangStmtVisitor.cpp */; };
+ 26D5B0C011B07550009A862E /* DWARFExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7ED810F1B86700F91463 /* DWARFExpression.cpp */; };
+ 26D5B0C111B07550009A862E /* Condition.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7EE710F1B88F00F91463 /* Condition.cpp */; };
+ 26D5B0C211B07550009A862E /* Host.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7EE810F1B88F00F91463 /* Host.mm */; };
+ 26D5B0C311B07550009A862E /* Mutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7EE910F1B88F00F91463 /* Mutex.cpp */; };
+ 26D5B0C411B07550009A862E /* CFCBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7EED10F1B8AD00F91463 /* CFCBundle.cpp */; };
+ 26D5B0C511B07550009A862E /* CFCData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7EEF10F1B8AD00F91463 /* CFCData.cpp */; };
+ 26D5B0C611B07550009A862E /* CFCMutableArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7EF110F1B8AD00F91463 /* CFCMutableArray.cpp */; };
+ 26D5B0C711B07550009A862E /* CFCMutableDictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7EF310F1B8AD00F91463 /* CFCMutableDictionary.cpp */; };
+ 26D5B0C811B07550009A862E /* CFCMutableSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7EF510F1B8AD00F91463 /* CFCMutableSet.cpp */; };
+ 26D5B0C911B07550009A862E /* CFCString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7EF810F1B8AD00F91463 /* CFCString.cpp */; };
+ 26D5B0CA11B07550009A862E /* CommandContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F0710F1B8DD00F91463 /* CommandContext.cpp */; };
+ 26D5B0CB11B07550009A862E /* CommandInterpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F0810F1B8DD00F91463 /* CommandInterpreter.cpp */; };
+ 26D5B0CC11B07550009A862E /* CommandObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F0910F1B8DD00F91463 /* CommandObject.cpp */; };
+ 26D5B0CD11B07550009A862E /* CommandReturnObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F0A10F1B8DD00F91463 /* CommandReturnObject.cpp */; };
+ 26D5B0CE11B07550009A862E /* StateVariable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F0B10F1B8DD00F91463 /* StateVariable.cpp */; };
+ 26D5B0CF11B07550009A862E /* ScriptInterpreterPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F0C10F1B8DD00F91463 /* ScriptInterpreterPython.cpp */; };
+ 26D5B0D011B07550009A862E /* Block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1310F1B8EC00F91463 /* Block.cpp */; };
+ 26D5B0D111B07550009A862E /* ClangASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1410F1B8EC00F91463 /* ClangASTContext.cpp */; settings = {COMPILER_FLAGS = "-fno-rtti"; }; };
+ 26D5B0D211B07550009A862E /* CompileUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1510F1B8EC00F91463 /* CompileUnit.cpp */; };
+ 26D5B0D311B07550009A862E /* Declaration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1610F1B8EC00F91463 /* Declaration.cpp */; };
+ 26D5B0D411B07550009A862E /* DWARFCallFrameInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1710F1B8EC00F91463 /* DWARFCallFrameInfo.cpp */; };
+ 26D5B0D511B07550009A862E /* Function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1810F1B8EC00F91463 /* Function.cpp */; };
+ 26D5B0D611B07550009A862E /* LineEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1910F1B8EC00F91463 /* LineEntry.cpp */; };
+ 26D5B0D711B07550009A862E /* LineTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1A10F1B8EC00F91463 /* LineTable.cpp */; };
+ 26D5B0D811B07550009A862E /* Symbol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1B10F1B8EC00F91463 /* Symbol.cpp */; };
+ 26D5B0D911B07550009A862E /* SymbolContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1C10F1B8EC00F91463 /* SymbolContext.cpp */; };
+ 26D5B0DA11B07550009A862E /* SymbolFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1D10F1B8EC00F91463 /* SymbolFile.cpp */; };
+ 26D5B0DB11B07550009A862E /* SymbolVendor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1E10F1B8EC00F91463 /* SymbolVendor.mm */; };
+ 26D5B0DC11B07550009A862E /* Symtab.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1F10F1B8EC00F91463 /* Symtab.cpp */; };
+ 26D5B0DD11B07550009A862E /* Type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F2010F1B8EC00F91463 /* Type.cpp */; };
+ 26D5B0DE11B07550009A862E /* TypeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F2110F1B8EC00F91463 /* TypeList.cpp */; };
+ 26D5B0DF11B07550009A862E /* Variable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F2210F1B8EC00F91463 /* Variable.cpp */; };
+ 26D5B0E011B07550009A862E /* VariableList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F2310F1B8EC00F91463 /* VariableList.cpp */; };
+ 26D5B0E111B07550009A862E /* ExecutionContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3510F1B90C00F91463 /* ExecutionContext.cpp */; };
+ 26D5B0E211B07550009A862E /* Process.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3610F1B90C00F91463 /* Process.cpp */; };
+ 26D5B0E311B07550009A862E /* RegisterContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3710F1B90C00F91463 /* RegisterContext.cpp */; };
+ 26D5B0E411B07550009A862E /* StackFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3810F1B90C00F91463 /* StackFrame.cpp */; };
+ 26D5B0E511B07550009A862E /* StackFrameList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3910F1B90C00F91463 /* StackFrameList.cpp */; };
+ 26D5B0E611B07550009A862E /* StackID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3A10F1B90C00F91463 /* StackID.cpp */; };
+ 26D5B0E711B07550009A862E /* Target.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3B10F1B90C00F91463 /* Target.cpp */; };
+ 26D5B0E811B07550009A862E /* TargetList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3C10F1B90C00F91463 /* TargetList.cpp */; };
+ 26D5B0E911B07550009A862E /* Thread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3D10F1B90C00F91463 /* Thread.cpp */; };
+ 26D5B0EA11B07550009A862E /* ThreadList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3E10F1B90C00F91463 /* ThreadList.cpp */; };
+ 26D5B0EB11B07550009A862E /* ThreadPlan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3F10F1B90C00F91463 /* ThreadPlan.cpp */; };
+ 26D5B0EC11B07550009A862E /* ObjectFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F4C10F1BC1A00F91463 /* ObjectFile.cpp */; };
+ 26D5B0ED11B07550009A862E /* ThreadPlanContinue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C847010F50EFC00BB2B04 /* ThreadPlanContinue.cpp */; };
+ 26D5B0EE11B07550009A862E /* ThreadPlanBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C847110F50EFC00BB2B04 /* ThreadPlanBase.cpp */; };
+ 26D5B0EF11B07550009A862E /* ThreadPlanStepInstruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C847210F50EFC00BB2B04 /* ThreadPlanStepInstruction.cpp */; };
+ 26D5B0F011B07550009A862E /* ThreadPlanStepOut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C847310F50EFC00BB2B04 /* ThreadPlanStepOut.cpp */; };
+ 26D5B0F111B07550009A862E /* ThreadPlanStepOverBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C847410F50EFC00BB2B04 /* ThreadPlanStepOverBreakpoint.cpp */; };
+ 26D5B0F211B07550009A862E /* ThreadPlanStepThrough.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C847510F50EFC00BB2B04 /* ThreadPlanStepThrough.cpp */; };
+ 26D5B0F311B07550009A862E /* ThreadPlanStepRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C847610F50EFC00BB2B04 /* ThreadPlanStepRange.cpp */; };
+ 26D5B0F411B07550009A862E /* DynamicLoaderMacOSXDYLD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C897A10F57C5600BB2B04 /* DynamicLoaderMacOSXDYLD.cpp */; };
+ 26D5B0F511B07550009A862E /* DynamicLoaderMacOSXDYLDLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C897C10F57C5600BB2B04 /* DynamicLoaderMacOSXDYLDLog.cpp */; };
+ 26D5B0F611B07550009A862E /* ObjectContainerUniversalMachO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C898010F57C5600BB2B04 /* ObjectContainerUniversalMachO.cpp */; };
+ 26D5B0F711B07550009A862E /* ObjectFileELF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C898510F57C5600BB2B04 /* ObjectFileELF.cpp */; };
+ 26D5B0F811B07550009A862E /* ObjectFileMachO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C898810F57C5600BB2B04 /* ObjectFileMachO.cpp */; };
+ 26D5B0F911B07550009A862E /* MachException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899210F57C5600BB2B04 /* MachException.cpp */; };
+ 26D5B0FA11B07550009A862E /* MachTask.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899410F57C5600BB2B04 /* MachTask.cpp */; };
+ 26D5B0FB11B07550009A862E /* MachThreadContext_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899710F57C5600BB2B04 /* MachThreadContext_arm.cpp */; };
+ 26D5B0FC11B07550009A862E /* MachThreadContext_i386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899910F57C5600BB2B04 /* MachThreadContext_i386.cpp */; };
+ 26D5B0FD11B07550009A862E /* MachThreadContext_x86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899B10F57C5600BB2B04 /* MachThreadContext_x86_64.cpp */; };
+ 26D5B0FE11B07550009A862E /* MachVMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899D10F57C5600BB2B04 /* MachVMMemory.cpp */; };
+ 26D5B0FF11B07550009A862E /* MachVMRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899F10F57C5600BB2B04 /* MachVMRegion.cpp */; };
+ 26D5B10011B07550009A862E /* ProcessControl-mig.defs in Sources */ = {isa = PBXBuildFile; fileRef = 260C89A110F57C5600BB2B04 /* ProcessControl-mig.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
+ 26D5B10111B07550009A862E /* ProcessMacOSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89A310F57C5600BB2B04 /* ProcessMacOSX.cpp */; };
+ 26D5B10211B07550009A862E /* ProcessMacOSXLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89A510F57C5600BB2B04 /* ProcessMacOSXLog.cpp */; };
+ 26D5B10311B07550009A862E /* RegisterContextMach_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89A910F57C5600BB2B04 /* RegisterContextMach_arm.cpp */; };
+ 26D5B10411B07550009A862E /* RegisterContextMach_i386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89AB10F57C5600BB2B04 /* RegisterContextMach_i386.cpp */; };
+ 26D5B10511B07550009A862E /* RegisterContextMach_x86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89AD10F57C5600BB2B04 /* RegisterContextMach_x86_64.cpp */; };
+ 26D5B10611B07550009A862E /* ThreadMacOSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89AF10F57C5600BB2B04 /* ThreadMacOSX.cpp */; };
+ 26D5B10711B07550009A862E /* DWARFAbbreviationDeclaration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89B310F57C5600BB2B04 /* DWARFAbbreviationDeclaration.cpp */; };
+ 26D5B10811B07550009A862E /* DWARFCompileUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89B710F57C5600BB2B04 /* DWARFCompileUnit.cpp */; };
+ 26D5B10911B07550009A862E /* DWARFDebugAbbrev.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89B910F57C5600BB2B04 /* DWARFDebugAbbrev.cpp */; };
+ 26D5B10A11B07550009A862E /* DWARFDebugAranges.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89BB10F57C5600BB2B04 /* DWARFDebugAranges.cpp */; };
+ 26D5B10B11B07550009A862E /* DWARFDebugArangeSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89BD10F57C5600BB2B04 /* DWARFDebugArangeSet.cpp */; };
+ 26D5B10C11B07550009A862E /* DWARFDebugInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89BF10F57C5600BB2B04 /* DWARFDebugInfo.cpp */; };
+ 26D5B10D11B07550009A862E /* DWARFDebugInfoEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89C110F57C5600BB2B04 /* DWARFDebugInfoEntry.cpp */; };
+ 26D5B10E11B07550009A862E /* DWARFDebugLine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89C310F57C5600BB2B04 /* DWARFDebugLine.cpp */; };
+ 26D5B10F11B07550009A862E /* DWARFDebugMacinfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89C510F57C5600BB2B04 /* DWARFDebugMacinfo.cpp */; };
+ 26D5B11011B07550009A862E /* DWARFDebugMacinfoEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89C710F57C5600BB2B04 /* DWARFDebugMacinfoEntry.cpp */; };
+ 26D5B11111B07550009A862E /* DWARFDebugPubnames.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89C910F57C5600BB2B04 /* DWARFDebugPubnames.cpp */; };
+ 26D5B11211B07550009A862E /* DWARFDebugPubnamesSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89CB10F57C5600BB2B04 /* DWARFDebugPubnamesSet.cpp */; };
+ 26D5B11311B07550009A862E /* DWARFDebugRanges.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89CD10F57C5600BB2B04 /* DWARFDebugRanges.cpp */; };
+ 26D5B11411B07550009A862E /* DWARFDefines.c in Sources */ = {isa = PBXBuildFile; fileRef = 260C89CF10F57C5600BB2B04 /* DWARFDefines.c */; };
+ 26D5B11511B07550009A862E /* DWARFDIECollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89D110F57C5600BB2B04 /* DWARFDIECollection.cpp */; };
+ 26D5B11611B07550009A862E /* DWARFFormValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89D310F57C5600BB2B04 /* DWARFFormValue.cpp */; };
+ 26D5B11711B07550009A862E /* DWARFLocationDescription.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89D510F57C5600BB2B04 /* DWARFLocationDescription.cpp */; };
+ 26D5B11811B07550009A862E /* DWARFLocationList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89D710F57C5600BB2B04 /* DWARFLocationList.cpp */; };
+ 26D5B11911B07550009A862E /* SymbolFileDWARF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89D910F57C5600BB2B04 /* SymbolFileDWARF.cpp */; };
+ 26D5B11A11B07550009A862E /* SymbolFileDWARFDebugMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89DB10F57C5600BB2B04 /* SymbolFileDWARFDebugMap.cpp */; };
+ 26D5B11B11B07550009A862E /* SymbolFileSymtab.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89DE10F57C5600BB2B04 /* SymbolFileSymtab.cpp */; };
+ 26D5B11C11B07550009A862E /* SymbolVendorMacOSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89E210F57C5600BB2B04 /* SymbolVendorMacOSX.cpp */; };
+ 26D5B11D11B07550009A862E /* CommandObjectUnalias.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A8B4EA310FD516400C68FF2 /* CommandObjectUnalias.cpp */; };
+ 26D5B11E11B07550009A862E /* ScriptInterpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A82010B10FFB49800182560 /* ScriptInterpreter.cpp */; };
+ 26D5B11F11B07550009A862E /* BreakpointResolverAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26D0DD5310FE555900271C65 /* BreakpointResolverAddress.cpp */; };
+ 26D5B12011B07550009A862E /* BreakpointResolverFileLine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26D0DD5410FE555900271C65 /* BreakpointResolverFileLine.cpp */; };
+ 26D5B12111B07550009A862E /* BreakpointResolverName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26D0DD5510FE555900271C65 /* BreakpointResolverName.cpp */; };
+ 26D5B12211B07550009A862E /* DisassemblerLLVM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C897410F57C5600BB2B04 /* DisassemblerLLVM.cpp */; };
+ 26D5B12311B07550009A862E /* ThreadPlanRunToAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CAFCE031101218900CA63DB /* ThreadPlanRunToAddress.cpp */; };
+ 26D5B12411B07550009A862E /* ThreadPlanShouldStopHere.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C43DEFA110641F300E55CBF /* ThreadPlanShouldStopHere.cpp */; };
+ 26D5B12511B07550009A862E /* ThreadPlanStepInRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C43DF8911069C3200E55CBF /* ThreadPlanStepInRange.cpp */; };
+ 26D5B12611B07550009A862E /* ThreadPlanStepOverRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C43DF8A11069C3200E55CBF /* ThreadPlanStepOverRange.cpp */; };
+ 26D5B12711B07550009A862E /* CommandObjectLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264AD83711095BA600E0B039 /* CommandObjectLog.cpp */; };
+ 26D5B12811B07550009A862E /* ValueObjectRegister.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264334381110F63100CDB6C6 /* ValueObjectRegister.cpp */; };
+ 26D5B12911B07550009A862E /* TimeValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26B4E28B112F5DCD00AB3F64 /* TimeValue.cpp */; };
+ 26D5B12A11B07550009A862E /* UUID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C81CA511335651004BDC5A /* UUID.cpp */; };
+ 26D5B12B11B07550009A862E /* ScriptInterpreterNone.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A2771FC1135A37500E6ADB6 /* ScriptInterpreterNone.cpp */; };
+ 26D5B12C11B07550009A862E /* CommandObjectCrossref.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DFBC57113B48F300DD817F /* CommandObjectCrossref.cpp */; };
+ 26D5B12D11B07550009A862E /* CommandObjectMultiword.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DFBC58113B48F300DD817F /* CommandObjectMultiword.cpp */; };
+ 26D5B12E11B07550009A862E /* CommandObjectRegexCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DFBC59113B48F300DD817F /* CommandObjectRegexCommand.cpp */; };
+ 26D5B12F11B07550009A862E /* Symbols.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2689B0B5113EE47E00A4AEDB /* Symbols.cpp */; };
+ 26D5B13011B07550009A862E /* Debugger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 263664921140A4930075843B /* Debugger.cpp */; };
+ 26D5B13111B07550009A862E /* ProcessGDBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE62FA1145F2130064CF93 /* ProcessGDBRemote.cpp */; };
+ 26D5B13211B07550009A862E /* ProcessGDBRemoteLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE62FC1145F2130064CF93 /* ProcessGDBRemoteLog.cpp */; };
+ 26D5B13311B07550009A862E /* ThreadGDBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE62FE1145F2130064CF93 /* ThreadGDBRemote.cpp */; };
+ 26D5B13411B07550009A862E /* GDBRemoteCommunication.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26FE25221146CADE00F4085A /* GDBRemoteCommunication.cpp */; };
+ 26D5B13511B07550009A862E /* GDBRemoteRegisterContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 261E18CD1148966100BADCD3 /* GDBRemoteRegisterContext.cpp */; };
+ 26D5B13611B07550009A862E /* UnixSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C00987011500B4300F316B0 /* UnixSignals.cpp */; };
+ 26D5B13711B07550009A862E /* LogChannelDWARF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26109B3B1155D70100CC3529 /* LogChannelDWARF.cpp */; };
+ 26D5B13811B07550009A862E /* PseudoTerminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2682F16A115EDA0D00CCFF99 /* PseudoTerminal.cpp */; };
+ 26D5B13911B07550009A862E /* LLDBWrapPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A4EEB511682AAC007A372A /* LLDBWrapPython.cpp */; };
+ 26D5B13A11B07550009A862E /* StringList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A35765F116E76B900E8ED2F /* StringList.cpp */; };
+ 26D5B13B11B07550009A862E /* CommandCompletions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C09CB74116BD98B00C7A725 /* CommandCompletions.cpp */; };
+ 26D5B13C11B07550009A862E /* AddressResolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC7034011752C6B0086C050 /* AddressResolver.cpp */; };
+ 26D5B13D11B07550009A862E /* AddressResolverFileLine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC7034211752C720086C050 /* AddressResolverFileLine.cpp */; };
+ 26D5B13E11B07550009A862E /* AddressResolverName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC7034411752C790086C050 /* AddressResolverName.cpp */; };
+ 26D5B13F11B07550009A862E /* ObjectContainerBSDArchive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A3B4AC1181454800381BC2 /* ObjectContainerBSDArchive.cpp */; };
+ 26D5B14011B07550009A862E /* CommandObjectBreakpointCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A42976211861AA600FE05CD /* CommandObjectBreakpointCommand.cpp */; };
+ 26D5B14111B07550009A862E /* InputReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AA69DB5118A027A00D753A0 /* InputReader.cpp */; };
+ 26D5B14211B07550009A862E /* CommandObjectFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2672D8461189055500FF4019 /* CommandObjectFrame.cpp */; };
+ 26D5B14311B07550009A862E /* ABISysV_x86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 493C63F11189203300914D5E /* ABISysV_x86_64.cpp */; };
+ 26D5B14411B07550009A862E /* ABI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 497E7B9D1188F6690065CCA1 /* ABI.cpp */; };
+ 26D5B14511B07550009A862E /* StringExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2660D9F611922A1300958FBD /* StringExtractor.cpp */; };
+ 26D5B14611B07550009A862E /* ThreadPlanStepUntil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2660D9FE11922A7F00958FBD /* ThreadPlanStepUntil.cpp */; };
+ 26D5B14711B07550009A862E /* ThreadPlanCallFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49EC3E98118F90AC00B1265E /* ThreadPlanCallFunction.cpp */; };
+ 26D5B14811B07550009A862E /* ClangFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */; };
+ 26D5B14911B07550009A862E /* RecordingMemoryManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */; settings = {COMPILER_FLAGS = "-fno-rtti"; }; };
+ 26D5B14A11B07550009A862E /* CommandObjectCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C98D3E4118FB9B100E575D0 /* CommandObjectCall.cpp */; };
+ 26D5B14B11B07550009A862E /* CommandObjectTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 269416AD119A024800FF2715 /* CommandObjectTarget.cpp */; };
+ 26D5B14C11B07550009A862E /* PathMappingList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 495BBACB119A0DBE00418BEA /* PathMappingList.cpp */; };
+ 26D5B14D11B07550009A862E /* StringExtractorGDBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2676A093119C93C8008A98EF /* StringExtractorGDBRemote.cpp */; };
+ 26D5B14E11B07550009A862E /* MacOSXLibunwindCallbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9654F79C1197DA1300F72B43 /* MacOSXLibunwindCallbacks.cpp */; };
+ 26D5B15011B07550009A862E /* Registers.s in Sources */ = {isa = PBXBuildFile; fileRef = 9654F7B51197DA3F00F72B43 /* Registers.s */; };
+ 26D5B15111B07550009A862E /* unw_getcontext.s in Sources */ = {isa = PBXBuildFile; fileRef = 9654F7BA1197DA3F00F72B43 /* unw_getcontext.s */; };
+ 26D5B15211B07550009A862E /* LibUnwindRegisterContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26B4666F11A2091600CF6220 /* LibUnwindRegisterContext.cpp */; };
+ 26D5B15311B07550009A862E /* ABIMacOSX_i386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 497650CE11A21BEE008DDB57 /* ABIMacOSX_i386.cpp */; };
+ 26D5B15411B07550009A862E /* ObjCTrampolineHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C51FF1611A4C486007C962F /* ObjCTrampolineHandler.cpp */; };
+ 26D5B15511B07550009A862E /* Baton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A0604811A5D03C00F75969 /* Baton.cpp */; };
+ 26D5B15611B07550009A862E /* CommandObjectArgs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 499F381F11A5B3F300F5CE02 /* CommandObjectArgs.cpp */; };
+ 26D5B15711B07550009A862E /* ThreadPlanStepThroughObjCTrampoline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CF4473E11A8687100EF971E /* ThreadPlanStepThroughObjCTrampoline.cpp */; };
+ 26D5B15911B07550009A862E /* UnwindLibUnwind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26E3EEBE11A98A1900FBADB6 /* UnwindLibUnwind.cpp */; };
+ 26D5B15A11B07550009A862E /* UnwindMacOSXFrameBackchain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26E3EEE311A9901300FBADB6 /* UnwindMacOSXFrameBackchain.cpp */; };
+ 26D5B15B11B07550009A862E /* RegisterContextMacOSXFrameBackchain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26E3EEF711A994E800FBADB6 /* RegisterContextMacOSXFrameBackchain.cpp */; };
+ 26D5B15C11B07550009A862E /* ObjCObjectPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49BF48DC11ADF356008863BD /* ObjCObjectPrinter.cpp */; };
+ 26D5B18E11B07979009A862E /* libuwind.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 9654F7B31197DA3F00F72B43 /* libuwind.cxx */; };
+ 26DE1E6B11616C2E00A093E2 /* lldb-forward-rtti.h in Headers */ = {isa = PBXBuildFile; fileRef = 26DE1E6911616C2E00A093E2 /* lldb-forward-rtti.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26DE1E6C11616C2E00A093E2 /* lldb-forward.h in Headers */ = {isa = PBXBuildFile; fileRef = 26DE1E6A11616C2E00A093E2 /* lldb-forward.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26DE204111618AB900A093E2 /* SBSymbolContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 26DE204011618AB900A093E2 /* SBSymbolContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26DE204311618ACA00A093E2 /* SBAddress.h in Headers */ = {isa = PBXBuildFile; fileRef = 26DE204211618ACA00A093E2 /* SBAddress.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26DE204511618ADA00A093E2 /* SBAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE204411618ADA00A093E2 /* SBAddress.cpp */; };
+ 26DE204711618AED00A093E2 /* SBSymbolContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE204611618AED00A093E2 /* SBSymbolContext.cpp */; };
+ 26DE204D11618E7A00A093E2 /* SBModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE204C11618E7A00A093E2 /* SBModule.cpp */; };
+ 26DE204F11618E9800A093E2 /* SBModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 26DE204E11618E9800A093E2 /* SBModule.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26DE205311618FAC00A093E2 /* SBFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 26DE205211618FAC00A093E2 /* SBFunction.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26DE205511618FB800A093E2 /* SBCompileUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = 26DE205411618FB800A093E2 /* SBCompileUnit.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26DE205711618FC500A093E2 /* SBBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 26DE205611618FC500A093E2 /* SBBlock.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26DE205911618FE700A093E2 /* SBLineEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 26DE205811618FE700A093E2 /* SBLineEntry.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26DE205B11618FF600A093E2 /* SBSymbol.h in Headers */ = {isa = PBXBuildFile; fileRef = 26DE205A11618FF600A093E2 /* SBSymbol.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 26DE205D1161901400A093E2 /* SBFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE205C1161901400A093E2 /* SBFunction.cpp */; };
+ 26DE205F1161901B00A093E2 /* SBCompileUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE205E1161901B00A093E2 /* SBCompileUnit.cpp */; };
+ 26DE20611161902700A093E2 /* SBBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE20601161902600A093E2 /* SBBlock.cpp */; };
+ 26DE20631161904200A093E2 /* SBLineEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE20621161904200A093E2 /* SBLineEntry.cpp */; };
+ 26DE20651161904E00A093E2 /* SBSymbol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE20641161904E00A093E2 /* SBSymbol.cpp */; };
+ 26F5C27710F3D9E4009D5894 /* Driver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26F5C27310F3D9E4009D5894 /* Driver.cpp */; };
+ 26F5C27810F3D9E4009D5894 /* IOChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26F5C27510F3D9E4009D5894 /* IOChannel.cpp */; };
+ 26F5C32510F3DF23009D5894 /* libpython2.6.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C32410F3DF23009D5894 /* libpython2.6.dylib */; };
+ 26F5C32C10F3DFDD009D5894 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C32A10F3DFDD009D5894 /* libedit.dylib */; };
+ 26F5C32D10F3DFDD009D5894 /* libtermcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C32B10F3DFDD009D5894 /* libtermcap.dylib */; };
+ 26F5C37510F3F61B009D5894 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C37410F3F61B009D5894 /* libobjc.dylib */; };
+ 26F5C39110F3FA26009D5894 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C39010F3FA26009D5894 /* CoreFoundation.framework */; };
+ 49D7072711B5AD03001AD875 /* ClangASTSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 49D7072611B5AD03001AD875 /* ClangASTSource.h */; };
+ 49D7072911B5AD11001AD875 /* ClangASTSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49D7072811B5AD11001AD875 /* ClangASTSource.cpp */; settings = {COMPILER_FLAGS = "-fno-rtti"; }; };
+ 49F1A74611B3388F003ED505 /* ClangExpressionDeclMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49F1A74511B3388F003ED505 /* ClangExpressionDeclMap.cpp */; };
+ 49F1A74A11B338AE003ED505 /* ClangExpressionDeclMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 49F1A74911B338AE003ED505 /* ClangExpressionDeclMap.h */; };
+ 4CA9637B11B6E99A00780E28 /* CommandObjectApropos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA9637911B6E99A00780E28 /* CommandObjectApropos.cpp */; };
+ 4CA9637C11B6E99A00780E28 /* CommandObjectApropos.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CA9637A11B6E99A00780E28 /* CommandObjectApropos.h */; };
+ 9A19A6AF1163BBB200E0D453 /* SBValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A19A6A51163BB7E00E0D453 /* SBValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */; };
+ 9A357583116CFDEE00E8ED2F /* SBValueList.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A357582116CFDEE00E8ED2F /* SBValueList.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 9A35758E116CFE0F00E8ED2F /* SBValueList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A35758D116CFE0F00E8ED2F /* SBValueList.cpp */; };
+ 9A357671116E7B5200E8ED2F /* SBStringList.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A357670116E7B5200E8ED2F /* SBStringList.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 9A357673116E7B6400E8ED2F /* SBStringList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A357672116E7B6400E8ED2F /* SBStringList.cpp */; };
+ 9A3576A8116E9AB700E8ED2F /* SBHostOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3576A7116E9AB700E8ED2F /* SBHostOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 9A3576AA116E9AC700E8ED2F /* SBHostOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A3576A9116E9AC700E8ED2F /* SBHostOS.cpp */; };
+ 9AA69DA61188F52100D753A0 /* PseudoTerminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2682F16A115EDA0D00CCFF99 /* PseudoTerminal.cpp */; };
+ 9AA69DAF118A023300D753A0 /* SBInputReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AA69DAE118A023300D753A0 /* SBInputReader.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 9AA69DB1118A024600D753A0 /* SBInputReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AA69DB0118A024600D753A0 /* SBInputReader.cpp */; };
+ 9AC7038E117674FB0086C050 /* SBInstruction.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AC7038D117674EB0086C050 /* SBInstruction.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 9AC70390117675270086C050 /* SBInstructionList.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AC7038F117675270086C050 /* SBInstructionList.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 9AC703AF117675410086C050 /* SBInstruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC703AE117675410086C050 /* SBInstruction.cpp */; };
+ 9AC703B1117675490086C050 /* SBInstructionList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC703B0117675490086C050 /* SBInstructionList.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 262CFC7111A450CB00946C6C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 265E9BE1115C2BAA00D0DCCB /* debugserver.xcodeproj */;
+ proxyType = 1;
+ remoteGlobalIDString = 26CE0593115C31C20022F371;
+ remoteInfo = debugserver;
+ };
+ 266803611160110D008E1FE4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 26680206115FD0ED008E1FE4;
+ remoteInfo = LLDB;
+ };
+ 26CE059F115C31E50022F371 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 265E9BE1115C2BAA00D0DCCB /* debugserver.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 26CE0594115C31C20022F371;
+ remoteInfo = "lldb-debugserver";
+ };
+ 26CE060F115C438C0022F371 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 265E9BE1115C2BAA00D0DCCB /* debugserver.xcodeproj */;
+ proxyType = 1;
+ remoteGlobalIDString = 26CE0593115C31C20022F371;
+ remoteInfo = "lldb-debugserver";
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 260223E7115F06D500A601A2 /* SBCommunication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBCommunication.h; path = include/lldb/API/SBCommunication.h; sourceTree = "<group>"; };
+ 260223E8115F06E500A601A2 /* SBCommunication.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBCommunication.cpp; path = source/API/SBCommunication.cpp; sourceTree = "<group>"; };
+ 26022531115F27FA00A601A2 /* SBFileSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBFileSpec.h; path = include/lldb/API/SBFileSpec.h; sourceTree = "<group>"; };
+ 26022532115F281400A601A2 /* SBFileSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBFileSpec.cpp; path = source/API/SBFileSpec.cpp; sourceTree = "<group>"; };
+ 260C847010F50EFC00BB2B04 /* ThreadPlanContinue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanContinue.cpp; path = source/Target/ThreadPlanContinue.cpp; sourceTree = "<group>"; };
+ 260C847110F50EFC00BB2B04 /* ThreadPlanBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanBase.cpp; path = source/Target/ThreadPlanBase.cpp; sourceTree = "<group>"; };
+ 260C847210F50EFC00BB2B04 /* ThreadPlanStepInstruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanStepInstruction.cpp; path = source/Target/ThreadPlanStepInstruction.cpp; sourceTree = "<group>"; };
+ 260C847310F50EFC00BB2B04 /* ThreadPlanStepOut.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanStepOut.cpp; path = source/Target/ThreadPlanStepOut.cpp; sourceTree = "<group>"; };
+ 260C847410F50EFC00BB2B04 /* ThreadPlanStepOverBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanStepOverBreakpoint.cpp; path = source/Target/ThreadPlanStepOverBreakpoint.cpp; sourceTree = "<group>"; };
+ 260C847510F50EFC00BB2B04 /* ThreadPlanStepThrough.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanStepThrough.cpp; path = source/Target/ThreadPlanStepThrough.cpp; sourceTree = "<group>"; };
+ 260C847610F50EFC00BB2B04 /* ThreadPlanStepRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanStepRange.cpp; path = source/Target/ThreadPlanStepRange.cpp; sourceTree = "<group>"; };
+ 260C847E10F50F0A00BB2B04 /* ThreadPlanContinue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanContinue.h; path = include/lldb/Target/ThreadPlanContinue.h; sourceTree = "<group>"; };
+ 260C847F10F50F0A00BB2B04 /* ThreadPlanBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanBase.h; path = include/lldb/Target/ThreadPlanBase.h; sourceTree = "<group>"; };
+ 260C848010F50F0A00BB2B04 /* ThreadPlanStepInstruction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepInstruction.h; path = include/lldb/Target/ThreadPlanStepInstruction.h; sourceTree = "<group>"; };
+ 260C848110F50F0A00BB2B04 /* ThreadPlanStepOut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepOut.h; path = include/lldb/Target/ThreadPlanStepOut.h; sourceTree = "<group>"; };
+ 260C848210F50F0A00BB2B04 /* ThreadPlanStepOverBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepOverBreakpoint.h; path = include/lldb/Target/ThreadPlanStepOverBreakpoint.h; sourceTree = "<group>"; };
+ 260C848310F50F0A00BB2B04 /* ThreadPlanStepThrough.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepThrough.h; path = include/lldb/Target/ThreadPlanStepThrough.h; sourceTree = "<group>"; };
+ 260C848410F50F0A00BB2B04 /* ThreadPlanStepRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepRange.h; path = include/lldb/Target/ThreadPlanStepRange.h; sourceTree = "<group>"; };
+ 260C876910F538E700BB2B04 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ 260C897410F57C5600BB2B04 /* DisassemblerLLVM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DisassemblerLLVM.cpp; sourceTree = "<group>"; };
+ 260C897510F57C5600BB2B04 /* DisassemblerLLVM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisassemblerLLVM.h; sourceTree = "<group>"; };
+ 260C897A10F57C5600BB2B04 /* DynamicLoaderMacOSXDYLD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicLoaderMacOSXDYLD.cpp; sourceTree = "<group>"; };
+ 260C897B10F57C5600BB2B04 /* DynamicLoaderMacOSXDYLD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicLoaderMacOSXDYLD.h; sourceTree = "<group>"; };
+ 260C897C10F57C5600BB2B04 /* DynamicLoaderMacOSXDYLDLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicLoaderMacOSXDYLDLog.cpp; sourceTree = "<group>"; };
+ 260C897D10F57C5600BB2B04 /* DynamicLoaderMacOSXDYLDLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicLoaderMacOSXDYLDLog.h; sourceTree = "<group>"; };
+ 260C898010F57C5600BB2B04 /* ObjectContainerUniversalMachO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectContainerUniversalMachO.cpp; sourceTree = "<group>"; };
+ 260C898110F57C5600BB2B04 /* ObjectContainerUniversalMachO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectContainerUniversalMachO.h; sourceTree = "<group>"; };
+ 260C898410F57C5600BB2B04 /* elf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = elf.h; sourceTree = "<group>"; };
+ 260C898510F57C5600BB2B04 /* ObjectFileELF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectFileELF.cpp; sourceTree = "<group>"; };
+ 260C898610F57C5600BB2B04 /* ObjectFileELF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectFileELF.h; sourceTree = "<group>"; };
+ 260C898810F57C5600BB2B04 /* ObjectFileMachO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectFileMachO.cpp; sourceTree = "<group>"; };
+ 260C898910F57C5600BB2B04 /* ObjectFileMachO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectFileMachO.h; sourceTree = "<group>"; };
+ 260C898D10F57C5600BB2B04 /* cc-swig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = "cc-swig"; sourceTree = "<group>"; };
+ 260C898E10F57C5600BB2B04 /* config.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = config.pl; sourceTree = "<group>"; };
+ 260C898F10F57C5600BB2B04 /* test-ProcessDebug.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = "test-ProcessDebug.pl"; sourceTree = "<group>"; };
+ 260C899210F57C5600BB2B04 /* MachException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachException.cpp; sourceTree = "<group>"; };
+ 260C899310F57C5600BB2B04 /* MachException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachException.h; sourceTree = "<group>"; };
+ 260C899410F57C5600BB2B04 /* MachTask.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachTask.cpp; sourceTree = "<group>"; };
+ 260C899510F57C5600BB2B04 /* MachTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachTask.h; sourceTree = "<group>"; };
+ 260C899610F57C5600BB2B04 /* MachThreadContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachThreadContext.h; sourceTree = "<group>"; };
+ 260C899710F57C5600BB2B04 /* MachThreadContext_arm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachThreadContext_arm.cpp; sourceTree = "<group>"; };
+ 260C899810F57C5600BB2B04 /* MachThreadContext_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachThreadContext_arm.h; sourceTree = "<group>"; };
+ 260C899910F57C5600BB2B04 /* MachThreadContext_i386.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachThreadContext_i386.cpp; sourceTree = "<group>"; };
+ 260C899A10F57C5600BB2B04 /* MachThreadContext_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachThreadContext_i386.h; sourceTree = "<group>"; };
+ 260C899B10F57C5600BB2B04 /* MachThreadContext_x86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachThreadContext_x86_64.cpp; sourceTree = "<group>"; };
+ 260C899C10F57C5600BB2B04 /* MachThreadContext_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachThreadContext_x86_64.h; sourceTree = "<group>"; };
+ 260C899D10F57C5600BB2B04 /* MachVMMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachVMMemory.cpp; sourceTree = "<group>"; };
+ 260C899E10F57C5600BB2B04 /* MachVMMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachVMMemory.h; sourceTree = "<group>"; };
+ 260C899F10F57C5600BB2B04 /* MachVMRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachVMRegion.cpp; sourceTree = "<group>"; };
+ 260C89A010F57C5600BB2B04 /* MachVMRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachVMRegion.h; sourceTree = "<group>"; };
+ 260C89A110F57C5600BB2B04 /* ProcessControl-mig.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = "ProcessControl-mig.defs"; sourceTree = "<group>"; };
+ 260C89A310F57C5600BB2B04 /* ProcessMacOSX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProcessMacOSX.cpp; sourceTree = "<group>"; };
+ 260C89A410F57C5600BB2B04 /* ProcessMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProcessMacOSX.h; sourceTree = "<group>"; };
+ 260C89A510F57C5600BB2B04 /* ProcessMacOSXLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProcessMacOSXLog.cpp; sourceTree = "<group>"; };
+ 260C89A610F57C5600BB2B04 /* ProcessMacOSXLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProcessMacOSXLog.h; sourceTree = "<group>"; };
+ 260C89A910F57C5600BB2B04 /* RegisterContextMach_arm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMach_arm.cpp; sourceTree = "<group>"; };
+ 260C89AA10F57C5600BB2B04 /* RegisterContextMach_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextMach_arm.h; sourceTree = "<group>"; };
+ 260C89AB10F57C5600BB2B04 /* RegisterContextMach_i386.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMach_i386.cpp; sourceTree = "<group>"; };
+ 260C89AC10F57C5600BB2B04 /* RegisterContextMach_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextMach_i386.h; sourceTree = "<group>"; };
+ 260C89AD10F57C5600BB2B04 /* RegisterContextMach_x86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMach_x86_64.cpp; sourceTree = "<group>"; };
+ 260C89AE10F57C5600BB2B04 /* RegisterContextMach_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextMach_x86_64.h; sourceTree = "<group>"; };
+ 260C89AF10F57C5600BB2B04 /* ThreadMacOSX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadMacOSX.cpp; sourceTree = "<group>"; };
+ 260C89B010F57C5600BB2B04 /* ThreadMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadMacOSX.h; sourceTree = "<group>"; };
+ 260C89B310F57C5600BB2B04 /* DWARFAbbreviationDeclaration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFAbbreviationDeclaration.cpp; sourceTree = "<group>"; };
+ 260C89B410F57C5600BB2B04 /* DWARFAbbreviationDeclaration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFAbbreviationDeclaration.h; sourceTree = "<group>"; };
+ 260C89B610F57C5600BB2B04 /* DWARFAttribute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFAttribute.h; sourceTree = "<group>"; };
+ 260C89B710F57C5600BB2B04 /* DWARFCompileUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFCompileUnit.cpp; sourceTree = "<group>"; };
+ 260C89B810F57C5600BB2B04 /* DWARFCompileUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFCompileUnit.h; sourceTree = "<group>"; };
+ 260C89B910F57C5600BB2B04 /* DWARFDebugAbbrev.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDebugAbbrev.cpp; sourceTree = "<group>"; };
+ 260C89BA10F57C5600BB2B04 /* DWARFDebugAbbrev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDebugAbbrev.h; sourceTree = "<group>"; };
+ 260C89BB10F57C5600BB2B04 /* DWARFDebugAranges.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDebugAranges.cpp; sourceTree = "<group>"; };
+ 260C89BC10F57C5600BB2B04 /* DWARFDebugAranges.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDebugAranges.h; sourceTree = "<group>"; };
+ 260C89BD10F57C5600BB2B04 /* DWARFDebugArangeSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDebugArangeSet.cpp; sourceTree = "<group>"; };
+ 260C89BE10F57C5600BB2B04 /* DWARFDebugArangeSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDebugArangeSet.h; sourceTree = "<group>"; };
+ 260C89BF10F57C5600BB2B04 /* DWARFDebugInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDebugInfo.cpp; sourceTree = "<group>"; };
+ 260C89C010F57C5600BB2B04 /* DWARFDebugInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDebugInfo.h; sourceTree = "<group>"; };
+ 260C89C110F57C5600BB2B04 /* DWARFDebugInfoEntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDebugInfoEntry.cpp; sourceTree = "<group>"; };
+ 260C89C210F57C5600BB2B04 /* DWARFDebugInfoEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDebugInfoEntry.h; sourceTree = "<group>"; };
+ 260C89C310F57C5600BB2B04 /* DWARFDebugLine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDebugLine.cpp; sourceTree = "<group>"; };
+ 260C89C410F57C5600BB2B04 /* DWARFDebugLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDebugLine.h; sourceTree = "<group>"; };
+ 260C89C510F57C5600BB2B04 /* DWARFDebugMacinfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDebugMacinfo.cpp; sourceTree = "<group>"; };
+ 260C89C610F57C5600BB2B04 /* DWARFDebugMacinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDebugMacinfo.h; sourceTree = "<group>"; };
+ 260C89C710F57C5600BB2B04 /* DWARFDebugMacinfoEntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDebugMacinfoEntry.cpp; sourceTree = "<group>"; };
+ 260C89C810F57C5600BB2B04 /* DWARFDebugMacinfoEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDebugMacinfoEntry.h; sourceTree = "<group>"; };
+ 260C89C910F57C5600BB2B04 /* DWARFDebugPubnames.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDebugPubnames.cpp; sourceTree = "<group>"; };
+ 260C89CA10F57C5600BB2B04 /* DWARFDebugPubnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDebugPubnames.h; sourceTree = "<group>"; };
+ 260C89CB10F57C5600BB2B04 /* DWARFDebugPubnamesSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDebugPubnamesSet.cpp; sourceTree = "<group>"; };
+ 260C89CC10F57C5600BB2B04 /* DWARFDebugPubnamesSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDebugPubnamesSet.h; sourceTree = "<group>"; };
+ 260C89CD10F57C5600BB2B04 /* DWARFDebugRanges.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDebugRanges.cpp; sourceTree = "<group>"; };
+ 260C89CE10F57C5600BB2B04 /* DWARFDebugRanges.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDebugRanges.h; sourceTree = "<group>"; };
+ 260C89CF10F57C5600BB2B04 /* DWARFDefines.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DWARFDefines.c; sourceTree = "<group>"; };
+ 260C89D010F57C5600BB2B04 /* DWARFDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDefines.h; sourceTree = "<group>"; };
+ 260C89D110F57C5600BB2B04 /* DWARFDIECollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDIECollection.cpp; sourceTree = "<group>"; };
+ 260C89D210F57C5600BB2B04 /* DWARFDIECollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDIECollection.h; sourceTree = "<group>"; };
+ 260C89D310F57C5600BB2B04 /* DWARFFormValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFFormValue.cpp; sourceTree = "<group>"; };
+ 260C89D410F57C5600BB2B04 /* DWARFFormValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFFormValue.h; sourceTree = "<group>"; };
+ 260C89D510F57C5600BB2B04 /* DWARFLocationDescription.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFLocationDescription.cpp; sourceTree = "<group>"; };
+ 260C89D610F57C5600BB2B04 /* DWARFLocationDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFLocationDescription.h; sourceTree = "<group>"; };
+ 260C89D710F57C5600BB2B04 /* DWARFLocationList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFLocationList.cpp; sourceTree = "<group>"; };
+ 260C89D810F57C5600BB2B04 /* DWARFLocationList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFLocationList.h; sourceTree = "<group>"; };
+ 260C89D910F57C5600BB2B04 /* SymbolFileDWARF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolFileDWARF.cpp; sourceTree = "<group>"; };
+ 260C89DA10F57C5600BB2B04 /* SymbolFileDWARF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolFileDWARF.h; sourceTree = "<group>"; };
+ 260C89DB10F57C5600BB2B04 /* SymbolFileDWARFDebugMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolFileDWARFDebugMap.cpp; sourceTree = "<group>"; };
+ 260C89DC10F57C5600BB2B04 /* SymbolFileDWARFDebugMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolFileDWARFDebugMap.h; sourceTree = "<group>"; };
+ 260C89DE10F57C5600BB2B04 /* SymbolFileSymtab.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolFileSymtab.cpp; sourceTree = "<group>"; };
+ 260C89DF10F57C5600BB2B04 /* SymbolFileSymtab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolFileSymtab.h; sourceTree = "<group>"; };
+ 260C89E210F57C5600BB2B04 /* SymbolVendorMacOSX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolVendorMacOSX.cpp; sourceTree = "<group>"; };
+ 260C89E310F57C5600BB2B04 /* SymbolVendorMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolVendorMacOSX.h; sourceTree = "<group>"; };
+ 26109B3B1155D70100CC3529 /* LogChannelDWARF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogChannelDWARF.cpp; sourceTree = "<group>"; };
+ 26109B3C1155D70100CC3529 /* LogChannelDWARF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogChannelDWARF.h; sourceTree = "<group>"; };
+ 261744771168585B005ADD65 /* SBType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBType.cpp; path = source/API/SBType.cpp; sourceTree = "<group>"; };
+ 2617447911685869005ADD65 /* SBType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBType.h; path = include/lldb/API/SBType.h; sourceTree = "<group>"; };
+ 261E18CC1148966100BADCD3 /* GDBRemoteRegisterContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GDBRemoteRegisterContext.h; path = "source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h"; sourceTree = "<group>"; };
+ 261E18CD1148966100BADCD3 /* GDBRemoteRegisterContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GDBRemoteRegisterContext.cpp; path = "source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp"; sourceTree = "<group>"; };
+ 263664921140A4930075843B /* Debugger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Debugger.cpp; path = source/Core/Debugger.cpp; sourceTree = "<group>"; };
+ 263664941140A4C10075843B /* Debugger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Debugger.h; path = include/lldb/Core/Debugger.h; sourceTree = "<group>"; };
+ 263FEDA5112CC1DA00E4C208 /* ThreadSafeSTLMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadSafeSTLMap.h; path = include/lldb/Core/ThreadSafeSTLMap.h; sourceTree = "<group>"; };
+ 264334381110F63100CDB6C6 /* ValueObjectRegister.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectRegister.cpp; path = source/Core/ValueObjectRegister.cpp; sourceTree = "<group>"; };
+ 2643343A1110F63C00CDB6C6 /* ValueObjectRegister.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectRegister.h; path = include/lldb/Core/ValueObjectRegister.h; sourceTree = "<group>"; };
+ 264AD83711095BA600E0B039 /* CommandObjectLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectLog.cpp; path = source/Commands/CommandObjectLog.cpp; sourceTree = "<group>"; };
+ 264AD83911095BBD00E0B039 /* CommandObjectLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectLog.h; path = source/Commands/CommandObjectLog.h; sourceTree = "<group>"; };
+ 265ABF6210F42EE900531910 /* DebugSymbols.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DebugSymbols.framework; path = /System/Library/PrivateFrameworks/DebugSymbols.framework; sourceTree = "<absolute>"; };
+ 265E9BE1115C2BAA00D0DCCB /* debugserver.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = debugserver.xcodeproj; path = tools/debugserver/debugserver.xcodeproj; sourceTree = "<group>"; };
+ 2660D9F611922A1300958FBD /* StringExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringExtractor.cpp; path = source/Utility/StringExtractor.cpp; sourceTree = "<group>"; };
+ 2660D9F711922A1300958FBD /* StringExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringExtractor.h; path = source/Utility/StringExtractor.h; sourceTree = "<group>"; };
+ 2660D9FE11922A7F00958FBD /* ThreadPlanStepUntil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanStepUntil.cpp; path = source/Target/ThreadPlanStepUntil.cpp; sourceTree = "<group>"; };
+ 26680207115FD0ED008E1FE4 /* LLDB.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LLDB.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 266960591199F4230075C61A /* build-llvm.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = "build-llvm.pl"; sourceTree = "<group>"; };
+ 2669605A1199F4230075C61A /* build-swig-wrapper-classes.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "build-swig-wrapper-classes.sh"; sourceTree = "<group>"; };
+ 2669605B1199F4230075C61A /* checkpoint-llvm.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = "checkpoint-llvm.pl"; sourceTree = "<group>"; };
+ 2669605C1199F4230075C61A /* finish-swig-wrapper-classes.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "finish-swig-wrapper-classes.sh"; sourceTree = "<group>"; };
+ 2669605D1199F4230075C61A /* install-lldb.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "install-lldb.sh"; sourceTree = "<group>"; };
+ 2669605E1199F4230075C61A /* lldb.swig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = lldb.swig; sourceTree = "<group>"; };
+ 266960601199F4230075C61A /* build-swig-Python.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "build-swig-Python.sh"; sourceTree = "<group>"; };
+ 266960611199F4230075C61A /* edit-swig-python-wrapper-file.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = "edit-swig-python-wrapper-file.py"; sourceTree = "<group>"; };
+ 266960621199F4230075C61A /* finish-swig-Python-lldb.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "finish-swig-Python-lldb.sh"; sourceTree = "<group>"; };
+ 266960631199F4230075C61A /* sed-sources */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = "sed-sources"; sourceTree = "<group>"; };
+ 2672D8461189055500FF4019 /* CommandObjectFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectFrame.cpp; path = source/Commands/CommandObjectFrame.cpp; sourceTree = "<group>"; };
+ 2672D8471189055500FF4019 /* CommandObjectFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectFrame.h; path = source/Commands/CommandObjectFrame.h; sourceTree = "<group>"; };
+ 2676A093119C93C8008A98EF /* StringExtractorGDBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringExtractorGDBRemote.cpp; path = source/Utility/StringExtractorGDBRemote.cpp; sourceTree = "<group>"; };
+ 2676A094119C93C8008A98EF /* StringExtractorGDBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringExtractorGDBRemote.h; path = source/Utility/StringExtractorGDBRemote.h; sourceTree = "<group>"; };
+ 2682F16A115EDA0D00CCFF99 /* PseudoTerminal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PseudoTerminal.cpp; path = source/Utility/PseudoTerminal.cpp; sourceTree = "<group>"; };
+ 2682F16B115EDA0D00CCFF99 /* PseudoTerminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PseudoTerminal.h; path = source/Utility/PseudoTerminal.h; sourceTree = "<group>"; };
+ 2682F284115EF3A700CCFF99 /* SBError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBError.cpp; path = source/API/SBError.cpp; sourceTree = "<group>"; };
+ 2682F286115EF3BD00CCFF99 /* SBError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBError.h; path = include/lldb/API/SBError.h; sourceTree = "<group>"; };
+ 2689B0A4113EE3CD00A4AEDB /* Symbols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Symbols.h; path = include/lldb/Host/Symbols.h; sourceTree = "<group>"; };
+ 2689B0B5113EE47E00A4AEDB /* Symbols.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Symbols.cpp; path = source/Host/macosx/Symbols.cpp; sourceTree = "<group>"; };
+ 268A813F115B19D000F645B0 /* UniqueCStringMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UniqueCStringMap.h; path = include/lldb/Core/UniqueCStringMap.h; sourceTree = "<group>"; };
+ 269416AD119A024800FF2715 /* CommandObjectTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectTarget.cpp; path = source/Commands/CommandObjectTarget.cpp; sourceTree = "<group>"; };
+ 269416AE119A024800FF2715 /* CommandObjectTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectTarget.h; path = source/Commands/CommandObjectTarget.h; sourceTree = "<group>"; };
+ 26A0604711A5BC7A00F75969 /* Baton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Baton.h; path = include/lldb/Core/Baton.h; sourceTree = "<group>"; };
+ 26A0604811A5D03C00F75969 /* Baton.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Baton.cpp; path = source/Core/Baton.cpp; sourceTree = "<group>"; };
+ 26A3B4AC1181454800381BC2 /* ObjectContainerBSDArchive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectContainerBSDArchive.cpp; sourceTree = "<group>"; };
+ 26A3B4AD1181454800381BC2 /* ObjectContainerBSDArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectContainerBSDArchive.h; sourceTree = "<group>"; };
+ 26A4EEB511682AAC007A372A /* LLDBWrapPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLDBWrapPython.cpp; path = source/LLDBWrapPython.cpp; sourceTree = "<group>"; };
+ 26B167A41123BF5500DC7B4F /* ThreadSafeValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadSafeValue.h; path = include/lldb/Core/ThreadSafeValue.h; sourceTree = "<group>"; };
+ 26B42B1E1187A92B0079C8C8 /* lldb-include.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-include.h"; path = "include/lldb/lldb-include.h"; sourceTree = "<group>"; };
+ 26B42C4C1187ABA50079C8C8 /* LLDB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLDB.h; path = include/lldb/API/LLDB.h; sourceTree = "<group>"; };
+ 26B4666F11A2091600CF6220 /* LibUnwindRegisterContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibUnwindRegisterContext.cpp; path = Utility/LibUnwindRegisterContext.cpp; sourceTree = "<group>"; };
+ 26B4667011A2091600CF6220 /* LibUnwindRegisterContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibUnwindRegisterContext.h; path = Utility/LibUnwindRegisterContext.h; sourceTree = "<group>"; };
+ 26B4E26E112F35F700AB3F64 /* TimeValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TimeValue.h; path = include/lldb/Host/TimeValue.h; sourceTree = "<group>"; };
+ 26B4E28B112F5DCD00AB3F64 /* TimeValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TimeValue.cpp; path = source/Host/macosx/TimeValue.cpp; sourceTree = "<group>"; };
+ 26BC7C2510F1B3BC00F91463 /* lldb-defines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-defines.h"; path = "include/lldb/lldb-defines.h"; sourceTree = "<group>"; };
+ 26BC7C2610F1B3BC00F91463 /* lldb-enumerations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-enumerations.h"; path = "include/lldb/lldb-enumerations.h"; sourceTree = "<group>"; };
+ 26BC7C2810F1B3BC00F91463 /* lldb-private-interfaces.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-private-interfaces.h"; path = "include/lldb/lldb-private-interfaces.h"; sourceTree = "<group>"; };
+ 26BC7C2910F1B3BC00F91463 /* lldb-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-types.h"; path = "include/lldb/lldb-types.h"; sourceTree = "<group>"; };
+ 26BC7C2A10F1B3BC00F91463 /* lldb-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-private.h"; path = "include/lldb/lldb-private.h"; sourceTree = "<group>"; };
+ 26BC7C5510F1B6E900F91463 /* Block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Block.h; path = include/lldb/Symbol/Block.h; sourceTree = "<group>"; };
+ 26BC7C5610F1B6E900F91463 /* ClangASTContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangASTContext.h; path = include/lldb/Symbol/ClangASTContext.h; sourceTree = "<group>"; };
+ 26BC7C5710F1B6E900F91463 /* CompileUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CompileUnit.h; path = include/lldb/Symbol/CompileUnit.h; sourceTree = "<group>"; };
+ 26BC7C5810F1B6E900F91463 /* Declaration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Declaration.h; path = include/lldb/Symbol/Declaration.h; sourceTree = "<group>"; };
+ 26BC7C5910F1B6E900F91463 /* DWARFCallFrameInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DWARFCallFrameInfo.h; path = include/lldb/Symbol/DWARFCallFrameInfo.h; sourceTree = "<group>"; };
+ 26BC7C5A10F1B6E900F91463 /* Function.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Function.h; path = include/lldb/Symbol/Function.h; sourceTree = "<group>"; };
+ 26BC7C5B10F1B6E900F91463 /* LineEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LineEntry.h; path = include/lldb/Symbol/LineEntry.h; sourceTree = "<group>"; };
+ 26BC7C5C10F1B6E900F91463 /* LineTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LineTable.h; path = include/lldb/Symbol/LineTable.h; sourceTree = "<group>"; };
+ 26BC7C5D10F1B6E900F91463 /* ObjectContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjectContainer.h; path = include/lldb/Symbol/ObjectContainer.h; sourceTree = "<group>"; };
+ 26BC7C5E10F1B6E900F91463 /* ObjectFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjectFile.h; path = include/lldb/Symbol/ObjectFile.h; sourceTree = "<group>"; };
+ 26BC7C5F10F1B6E900F91463 /* Symbol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Symbol.h; path = include/lldb/Symbol/Symbol.h; sourceTree = "<group>"; };
+ 26BC7C6010F1B6E900F91463 /* SymbolContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolContext.h; path = include/lldb/Symbol/SymbolContext.h; sourceTree = "<group>"; };
+ 26BC7C6110F1B6E900F91463 /* SymbolContextScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolContextScope.h; path = include/lldb/Symbol/SymbolContextScope.h; sourceTree = "<group>"; };
+ 26BC7C6210F1B6E900F91463 /* SymbolFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolFile.h; path = include/lldb/Symbol/SymbolFile.h; sourceTree = "<group>"; };
+ 26BC7C6310F1B6E900F91463 /* SymbolVendor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolVendor.h; path = include/lldb/Symbol/SymbolVendor.h; sourceTree = "<group>"; };
+ 26BC7C6410F1B6E900F91463 /* Symtab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Symtab.h; path = include/lldb/Symbol/Symtab.h; sourceTree = "<group>"; };
+ 26BC7C6510F1B6E900F91463 /* Type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Type.h; path = include/lldb/Symbol/Type.h; sourceTree = "<group>"; };
+ 26BC7C6610F1B6E900F91463 /* TypeList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeList.h; path = include/lldb/Symbol/TypeList.h; sourceTree = "<group>"; };
+ 26BC7C6710F1B6E900F91463 /* Variable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Variable.h; path = include/lldb/Symbol/Variable.h; sourceTree = "<group>"; };
+ 26BC7C6810F1B6E900F91463 /* VariableList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VariableList.h; path = include/lldb/Symbol/VariableList.h; sourceTree = "<group>"; };
+ 26BC7CED10F1B71400F91463 /* StoppointCallbackContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StoppointCallbackContext.h; path = include/lldb/Breakpoint/StoppointCallbackContext.h; sourceTree = "<group>"; };
+ 26BC7CEE10F1B71400F91463 /* Breakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Breakpoint.h; path = include/lldb/Breakpoint/Breakpoint.h; sourceTree = "<group>"; };
+ 26BC7CEF10F1B71400F91463 /* BreakpointID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointID.h; path = include/lldb/Breakpoint/BreakpointID.h; sourceTree = "<group>"; };
+ 26BC7CF010F1B71400F91463 /* BreakpointIDList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointIDList.h; path = include/lldb/Breakpoint/BreakpointIDList.h; sourceTree = "<group>"; };
+ 26BC7CF110F1B71400F91463 /* BreakpointList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointList.h; path = include/lldb/Breakpoint/BreakpointList.h; sourceTree = "<group>"; };
+ 26BC7CF210F1B71400F91463 /* BreakpointLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointLocation.h; path = include/lldb/Breakpoint/BreakpointLocation.h; sourceTree = "<group>"; };
+ 26BC7CF310F1B71400F91463 /* BreakpointLocationCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointLocationCollection.h; path = include/lldb/Breakpoint/BreakpointLocationCollection.h; sourceTree = "<group>"; };
+ 26BC7CF410F1B71400F91463 /* BreakpointLocationList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointLocationList.h; path = include/lldb/Breakpoint/BreakpointLocationList.h; sourceTree = "<group>"; };
+ 26BC7CF510F1B71400F91463 /* BreakpointOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointOptions.h; path = include/lldb/Breakpoint/BreakpointOptions.h; sourceTree = "<group>"; };
+ 26BC7CF610F1B71400F91463 /* BreakpointResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointResolver.h; path = include/lldb/Breakpoint/BreakpointResolver.h; sourceTree = "<group>"; };
+ 26BC7CF710F1B71400F91463 /* BreakpointSite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointSite.h; path = include/lldb/Breakpoint/BreakpointSite.h; sourceTree = "<group>"; };
+ 26BC7CF810F1B71400F91463 /* BreakpointSiteList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointSiteList.h; path = include/lldb/Breakpoint/BreakpointSiteList.h; sourceTree = "<group>"; };
+ 26BC7CF910F1B71400F91463 /* SearchFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SearchFilter.h; path = include/lldb/Core/SearchFilter.h; sourceTree = "<group>"; };
+ 26BC7CFA10F1B71400F91463 /* Stoppoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Stoppoint.h; path = include/lldb/Breakpoint/Stoppoint.h; sourceTree = "<group>"; };
+ 26BC7CFB10F1B71400F91463 /* StoppointLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StoppointLocation.h; path = include/lldb/Breakpoint/StoppointLocation.h; sourceTree = "<group>"; };
+ 26BC7CFC10F1B71400F91463 /* WatchpointLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WatchpointLocation.h; path = include/lldb/Breakpoint/WatchpointLocation.h; sourceTree = "<group>"; };
+ 26BC7D1010F1B76300F91463 /* CommandObjectAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectAdd.h; path = source/Commands/CommandObjectAdd.h; sourceTree = "<group>"; };
+ 26BC7D1110F1B76300F91463 /* CommandObjectAlias.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectAlias.h; path = source/Commands/CommandObjectAlias.h; sourceTree = "<group>"; };
+ 26BC7D1210F1B76300F91463 /* CommandObjectAppend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectAppend.h; path = source/Commands/CommandObjectAppend.h; sourceTree = "<group>"; };
+ 26BC7D1410F1B76300F91463 /* CommandObjectBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectBreakpoint.h; path = source/Commands/CommandObjectBreakpoint.h; sourceTree = "<group>"; };
+ 26BC7D1610F1B76300F91463 /* CommandObjectDelete.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectDelete.h; path = source/Commands/CommandObjectDelete.h; sourceTree = "<group>"; };
+ 26BC7D1710F1B76300F91463 /* CommandObjectDisassemble.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectDisassemble.h; path = source/Commands/CommandObjectDisassemble.h; sourceTree = "<group>"; };
+ 26BC7D1810F1B76300F91463 /* CommandObjectExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectExpression.h; path = source/Commands/CommandObjectExpression.h; sourceTree = "<group>"; };
+ 26BC7D1910F1B76300F91463 /* CommandObjectFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectFile.h; path = source/Commands/CommandObjectFile.h; sourceTree = "<group>"; };
+ 26BC7D1A10F1B76300F91463 /* CommandObjectHelp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectHelp.h; path = source/Commands/CommandObjectHelp.h; sourceTree = "<group>"; };
+ 26BC7D1B10F1B76300F91463 /* CommandObjectImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectImage.h; path = source/Commands/CommandObjectImage.h; sourceTree = "<group>"; };
+ 26BC7D1C10F1B76300F91463 /* CommandObjectInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectInfo.h; path = source/Commands/CommandObjectInfo.h; sourceTree = "<group>"; };
+ 26BC7D1D10F1B76300F91463 /* CommandObjectMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectMemory.h; path = source/Commands/CommandObjectMemory.h; sourceTree = "<group>"; };
+ 26BC7D1F10F1B76300F91463 /* CommandObjectProcess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectProcess.h; path = source/Commands/CommandObjectProcess.h; sourceTree = "<group>"; };
+ 26BC7D2010F1B76300F91463 /* CommandObjectQuit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectQuit.h; path = source/Commands/CommandObjectQuit.h; sourceTree = "<group>"; };
+ 26BC7D2210F1B76300F91463 /* CommandObjectRegister.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectRegister.h; path = source/Commands/CommandObjectRegister.h; sourceTree = "<group>"; };
+ 26BC7D2310F1B76300F91463 /* CommandObjectRemove.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectRemove.h; path = source/Commands/CommandObjectRemove.h; sourceTree = "<group>"; };
+ 26BC7D2410F1B76300F91463 /* CommandObjectScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectScript.h; path = source/Commands/CommandObjectScript.h; sourceTree = "<group>"; };
+ 26BC7D2510F1B76300F91463 /* CommandObjectSelect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectSelect.h; path = source/Commands/CommandObjectSelect.h; sourceTree = "<group>"; };
+ 26BC7D2610F1B76300F91463 /* CommandObjectSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectSet.h; path = source/Commands/CommandObjectSet.h; sourceTree = "<group>"; };
+ 26BC7D2710F1B76300F91463 /* CommandObjectSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectSettings.h; path = source/Commands/CommandObjectSettings.h; sourceTree = "<group>"; };
+ 26BC7D2810F1B76300F91463 /* CommandObjectShow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectShow.h; path = source/Commands/CommandObjectShow.h; sourceTree = "<group>"; };
+ 26BC7D2910F1B76300F91463 /* CommandObjectSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectSource.h; path = source/Commands/CommandObjectSource.h; sourceTree = "<group>"; };
+ 26BC7D2A10F1B76300F91463 /* CommandObjectSourceFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectSourceFile.h; path = source/Commands/CommandObjectSourceFile.h; sourceTree = "<group>"; };
+ 26BC7D2B10F1B76300F91463 /* CommandObjectStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectStatus.h; path = source/Commands/CommandObjectStatus.h; sourceTree = "<group>"; };
+ 26BC7D2C10F1B76300F91463 /* CommandObjectSyntax.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectSyntax.h; path = source/Commands/CommandObjectSyntax.h; sourceTree = "<group>"; };
+ 26BC7D2D10F1B76300F91463 /* CommandObjectThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectThread.h; path = source/Commands/CommandObjectThread.h; sourceTree = "<group>"; };
+ 26BC7D2E10F1B76300F91463 /* CommandObjectTranslate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectTranslate.h; path = source/Commands/CommandObjectTranslate.h; sourceTree = "<group>"; };
+ 26BC7D2F10F1B76300F91463 /* CommandObjectVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectVariable.h; path = source/Commands/CommandObjectVariable.h; sourceTree = "<group>"; };
+ 26BC7D5010F1B77400F91463 /* Address.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Address.h; path = include/lldb/Core/Address.h; sourceTree = "<group>"; };
+ 26BC7D5110F1B77400F91463 /* AddressRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AddressRange.h; path = include/lldb/Core/AddressRange.h; sourceTree = "<group>"; };
+ 26BC7D5210F1B77400F91463 /* ArchSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ArchSpec.h; path = include/lldb/Core/ArchSpec.h; sourceTree = "<group>"; };
+ 26BC7D5310F1B77400F91463 /* Args.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Args.h; path = include/lldb/Core/Args.h; sourceTree = "<group>"; };
+ 26BC7D5410F1B77400F91463 /* Broadcaster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Broadcaster.h; path = include/lldb/Core/Broadcaster.h; sourceTree = "<group>"; };
+ 26BC7D5510F1B77400F91463 /* ClangForward.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangForward.h; path = include/lldb/Core/ClangForward.h; sourceTree = "<group>"; };
+ 26BC7D5610F1B77400F91463 /* Communication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Communication.h; path = include/lldb/Core/Communication.h; sourceTree = "<group>"; };
+ 26BC7D5710F1B77400F91463 /* Connection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Connection.h; path = include/lldb/Core/Connection.h; sourceTree = "<group>"; };
+ 26BC7D5810F1B77400F91463 /* ConnectionFileDescriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConnectionFileDescriptor.h; path = include/lldb/Core/ConnectionFileDescriptor.h; sourceTree = "<group>"; };
+ 26BC7D5910F1B77400F91463 /* DataBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataBuffer.h; path = include/lldb/Core/DataBuffer.h; sourceTree = "<group>"; };
+ 26BC7D5A10F1B77400F91463 /* DataExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataExtractor.h; path = include/lldb/Core/DataExtractor.h; sourceTree = "<group>"; };
+ 26BC7D5B10F1B77400F91463 /* DataBufferHeap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataBufferHeap.h; path = include/lldb/Core/DataBufferHeap.h; sourceTree = "<group>"; };
+ 26BC7D5C10F1B77400F91463 /* DataBufferMemoryMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataBufferMemoryMap.h; path = include/lldb/Core/DataBufferMemoryMap.h; sourceTree = "<group>"; };
+ 26BC7D5D10F1B77400F91463 /* lldb-private-log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-private-log.h"; path = "include/lldb/lldb-private-log.h"; sourceTree = "<group>"; };
+ 26BC7D5E10F1B77400F91463 /* Disassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Disassembler.h; path = include/lldb/Core/Disassembler.h; sourceTree = "<group>"; };
+ 26BC7D5F10F1B77400F91463 /* dwarf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf.h; path = include/lldb/Core/dwarf.h; sourceTree = "<group>"; };
+ 26BC7D6010F1B77400F91463 /* Error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Error.h; path = include/lldb/Core/Error.h; sourceTree = "<group>"; };
+ 26BC7D6110F1B77400F91463 /* Event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Event.h; path = include/lldb/Core/Event.h; sourceTree = "<group>"; };
+ 26BC7D6210F1B77400F91463 /* FileSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileSpec.h; path = include/lldb/Core/FileSpec.h; sourceTree = "<group>"; };
+ 26BC7D6310F1B77400F91463 /* FileSpecList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileSpecList.h; path = include/lldb/Core/FileSpecList.h; sourceTree = "<group>"; };
+ 26BC7D6410F1B77400F91463 /* Flags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Flags.h; path = include/lldb/Core/Flags.h; sourceTree = "<group>"; };
+ 26BC7D6510F1B77400F91463 /* IOStreamMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IOStreamMacros.h; path = include/lldb/Core/IOStreamMacros.h; sourceTree = "<group>"; };
+ 26BC7D6610F1B77400F91463 /* Language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Language.h; path = include/lldb/Core/Language.h; sourceTree = "<group>"; };
+ 26BC7D6710F1B77400F91463 /* Listener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Listener.h; path = include/lldb/Core/Listener.h; sourceTree = "<group>"; };
+ 26BC7D6810F1B77400F91463 /* Log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Log.h; path = include/lldb/Core/Log.h; sourceTree = "<group>"; };
+ 26BC7D6910F1B77400F91463 /* Mangled.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mangled.h; path = include/lldb/Core/Mangled.h; sourceTree = "<group>"; };
+ 26BC7D6A10F1B77400F91463 /* Module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Module.h; path = include/lldb/Core/Module.h; sourceTree = "<group>"; };
+ 26BC7D6B10F1B77400F91463 /* ModuleChild.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ModuleChild.h; path = include/lldb/Core/ModuleChild.h; sourceTree = "<group>"; };
+ 26BC7D6C10F1B77400F91463 /* ModuleList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ModuleList.h; path = include/lldb/Core/ModuleList.h; sourceTree = "<group>"; };
+ 26BC7D6D10F1B77400F91463 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Options.h; path = include/lldb/Core/Options.h; sourceTree = "<group>"; };
+ 26BC7D7010F1B77400F91463 /* PluginInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PluginInterface.h; path = include/lldb/Core/PluginInterface.h; sourceTree = "<group>"; };
+ 26BC7D7110F1B77400F91463 /* PluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PluginManager.h; path = include/lldb/Core/PluginManager.h; sourceTree = "<group>"; };
+ 26BC7D7310F1B77400F91463 /* RegularExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegularExpression.h; path = include/lldb/Core/RegularExpression.h; sourceTree = "<group>"; };
+ 26BC7D7410F1B77400F91463 /* Scalar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Scalar.h; path = include/lldb/Core/Scalar.h; sourceTree = "<group>"; };
+ 26BC7D7510F1B77400F91463 /* Section.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Section.h; path = include/lldb/Core/Section.h; sourceTree = "<group>"; };
+ 26BC7D7610F1B77400F91463 /* SourceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SourceManager.h; path = include/lldb/Core/SourceManager.h; sourceTree = "<group>"; };
+ 26BC7D7710F1B77400F91463 /* State.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = State.h; path = include/lldb/Core/State.h; sourceTree = "<group>"; };
+ 26BC7D7810F1B77400F91463 /* STLUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STLUtils.h; path = include/lldb/Core/STLUtils.h; sourceTree = "<group>"; };
+ 26BC7D7910F1B77400F91463 /* Stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Stream.h; path = include/lldb/Core/Stream.h; sourceTree = "<group>"; };
+ 26BC7D7A10F1B77400F91463 /* StreamFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamFile.h; path = include/lldb/Core/StreamFile.h; sourceTree = "<group>"; };
+ 26BC7D7B10F1B77400F91463 /* StreamString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamString.h; path = include/lldb/Core/StreamString.h; sourceTree = "<group>"; };
+ 26BC7D7C10F1B77400F91463 /* ConstString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConstString.h; path = include/lldb/Core/ConstString.h; sourceTree = "<group>"; };
+ 26BC7D7E10F1B77400F91463 /* Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Timer.h; path = include/lldb/Core/Timer.h; sourceTree = "<group>"; };
+ 26BC7D7F10F1B77400F91463 /* TTYState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TTYState.h; path = include/lldb/Core/TTYState.h; sourceTree = "<group>"; };
+ 26BC7D8010F1B77400F91463 /* UserID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UserID.h; path = include/lldb/Core/UserID.h; sourceTree = "<group>"; };
+ 26BC7D8110F1B77400F91463 /* Value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Value.h; path = include/lldb/Core/Value.h; sourceTree = "<group>"; };
+ 26BC7D8210F1B77400F91463 /* ValueObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObject.h; path = include/lldb/Core/ValueObject.h; sourceTree = "<group>"; };
+ 26BC7D8310F1B77400F91463 /* ValueObjectChild.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectChild.h; path = include/lldb/Core/ValueObjectChild.h; sourceTree = "<group>"; };
+ 26BC7D8410F1B77400F91463 /* ValueObjectList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectList.h; path = include/lldb/Core/ValueObjectList.h; sourceTree = "<group>"; };
+ 26BC7D8510F1B77400F91463 /* ValueObjectVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectVariable.h; path = include/lldb/Core/ValueObjectVariable.h; sourceTree = "<group>"; };
+ 26BC7D8610F1B77400F91463 /* VMRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VMRange.h; path = include/lldb/Core/VMRange.h; sourceTree = "<group>"; };
+ 26BC7DC010F1B79500F91463 /* ClangExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangExpression.h; path = include/lldb/Expression/ClangExpression.h; sourceTree = "<group>"; };
+ 26BC7DC110F1B79500F91463 /* ClangExpressionVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangExpressionVariable.h; path = include/lldb/Expression/ClangExpressionVariable.h; sourceTree = "<group>"; };
+ 26BC7DC210F1B79500F91463 /* ClangStmtVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangStmtVisitor.h; path = include/lldb/Expression/ClangStmtVisitor.h; sourceTree = "<group>"; };
+ 26BC7DC310F1B79500F91463 /* DWARFExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DWARFExpression.h; path = include/lldb/Expression/DWARFExpression.h; sourceTree = "<group>"; };
+ 26BC7DD210F1B7D500F91463 /* Condition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Condition.h; path = include/lldb/Host/Condition.h; sourceTree = "<group>"; };
+ 26BC7DD310F1B7D500F91463 /* Endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Endian.h; path = include/lldb/Host/Endian.h; sourceTree = "<group>"; };
+ 26BC7DD410F1B7D500F91463 /* Host.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Host.h; path = include/lldb/Host/Host.h; sourceTree = "<group>"; };
+ 26BC7DD510F1B7D500F91463 /* Mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mutex.h; path = include/lldb/Host/Mutex.h; sourceTree = "<group>"; };
+ 26BC7DD610F1B7D500F91463 /* Predicate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Predicate.h; path = include/lldb/Host/Predicate.h; sourceTree = "<group>"; };
+ 26BC7DD710F1B7D500F91463 /* Types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Types.h; path = include/lldb/Host/Types.h; sourceTree = "<group>"; };
+ 26BC7DE110F1B7F900F91463 /* CommandContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandContext.h; path = include/lldb/Interpreter/CommandContext.h; sourceTree = "<group>"; };
+ 26BC7DE210F1B7F900F91463 /* CommandInterpreter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandInterpreter.h; path = include/lldb/Interpreter/CommandInterpreter.h; sourceTree = "<group>"; };
+ 26BC7DE310F1B7F900F91463 /* CommandObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObject.h; path = include/lldb/Interpreter/CommandObject.h; sourceTree = "<group>"; };
+ 26BC7DE410F1B7F900F91463 /* CommandReturnObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandReturnObject.h; path = include/lldb/Interpreter/CommandReturnObject.h; sourceTree = "<group>"; };
+ 26BC7DE510F1B7F900F91463 /* ScriptInterpreter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScriptInterpreter.h; path = include/lldb/Interpreter/ScriptInterpreter.h; sourceTree = "<group>"; };
+ 26BC7DE610F1B7F900F91463 /* ScriptInterpreterPython.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScriptInterpreterPython.h; path = include/lldb/Interpreter/ScriptInterpreterPython.h; sourceTree = "<group>"; };
+ 26BC7DE710F1B7F900F91463 /* StateVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StateVariable.h; path = include/lldb/Interpreter/StateVariable.h; sourceTree = "<group>"; };
+ 26BC7DF110F1B81A00F91463 /* DynamicLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DynamicLoader.h; path = include/lldb/Target/DynamicLoader.h; sourceTree = "<group>"; };
+ 26BC7DF210F1B81A00F91463 /* ExecutionContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExecutionContext.h; path = include/lldb/Target/ExecutionContext.h; sourceTree = "<group>"; };
+ 26BC7DF310F1B81A00F91463 /* Process.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Process.h; path = include/lldb/Target/Process.h; sourceTree = "<group>"; };
+ 26BC7DF410F1B81A00F91463 /* RegisterContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContext.h; path = include/lldb/Target/RegisterContext.h; sourceTree = "<group>"; };
+ 26BC7DF510F1B81A00F91463 /* StackFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackFrame.h; path = include/lldb/Target/StackFrame.h; sourceTree = "<group>"; };
+ 26BC7DF610F1B81A00F91463 /* StackFrameList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackFrameList.h; path = include/lldb/Target/StackFrameList.h; sourceTree = "<group>"; };
+ 26BC7DF710F1B81A00F91463 /* StackID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackID.h; path = include/lldb/Target/StackID.h; sourceTree = "<group>"; };
+ 26BC7DF810F1B81A00F91463 /* Target.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Target.h; path = include/lldb/Target/Target.h; sourceTree = "<group>"; };
+ 26BC7DF910F1B81A00F91463 /* TargetList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TargetList.h; path = include/lldb/Target/TargetList.h; sourceTree = "<group>"; };
+ 26BC7DFA10F1B81A00F91463 /* Thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Thread.h; path = include/lldb/Target/Thread.h; sourceTree = "<group>"; };
+ 26BC7DFB10F1B81A00F91463 /* ThreadList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadList.h; path = include/lldb/Target/ThreadList.h; sourceTree = "<group>"; };
+ 26BC7DFC10F1B81A00F91463 /* ThreadPlan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlan.h; path = include/lldb/Target/ThreadPlan.h; sourceTree = "<group>"; };
+ 26BC7E0910F1B83100F91463 /* StoppointCallbackContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StoppointCallbackContext.cpp; path = source/Breakpoint/StoppointCallbackContext.cpp; sourceTree = "<group>"; };
+ 26BC7E0A10F1B83100F91463 /* Breakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Breakpoint.cpp; path = source/Breakpoint/Breakpoint.cpp; sourceTree = "<group>"; };
+ 26BC7E0B10F1B83100F91463 /* BreakpointID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointID.cpp; path = source/Breakpoint/BreakpointID.cpp; sourceTree = "<group>"; };
+ 26BC7E0C10F1B83100F91463 /* BreakpointIDList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointIDList.cpp; path = source/Breakpoint/BreakpointIDList.cpp; sourceTree = "<group>"; };
+ 26BC7E0D10F1B83100F91463 /* BreakpointList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointList.cpp; path = source/Breakpoint/BreakpointList.cpp; sourceTree = "<group>"; };
+ 26BC7E0E10F1B83100F91463 /* BreakpointLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointLocation.cpp; path = source/Breakpoint/BreakpointLocation.cpp; sourceTree = "<group>"; };
+ 26BC7E0F10F1B83100F91463 /* BreakpointLocationCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointLocationCollection.cpp; path = source/Breakpoint/BreakpointLocationCollection.cpp; sourceTree = "<group>"; };
+ 26BC7E1010F1B83100F91463 /* BreakpointLocationList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointLocationList.cpp; path = source/Breakpoint/BreakpointLocationList.cpp; sourceTree = "<group>"; };
+ 26BC7E1110F1B83100F91463 /* BreakpointOptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointOptions.cpp; path = source/Breakpoint/BreakpointOptions.cpp; sourceTree = "<group>"; };
+ 26BC7E1210F1B83100F91463 /* BreakpointResolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointResolver.cpp; path = source/Breakpoint/BreakpointResolver.cpp; sourceTree = "<group>"; };
+ 26BC7E1310F1B83100F91463 /* BreakpointSite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointSite.cpp; path = source/Breakpoint/BreakpointSite.cpp; sourceTree = "<group>"; };
+ 26BC7E1410F1B83100F91463 /* BreakpointSiteList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointSiteList.cpp; path = source/Breakpoint/BreakpointSiteList.cpp; sourceTree = "<group>"; };
+ 26BC7E1510F1B83100F91463 /* SearchFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SearchFilter.cpp; path = source/Core/SearchFilter.cpp; sourceTree = "<group>"; };
+ 26BC7E1610F1B83100F91463 /* Stoppoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Stoppoint.cpp; path = source/Breakpoint/Stoppoint.cpp; sourceTree = "<group>"; };
+ 26BC7E1710F1B83100F91463 /* StoppointLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StoppointLocation.cpp; path = source/Breakpoint/StoppointLocation.cpp; sourceTree = "<group>"; };
+ 26BC7E1810F1B83100F91463 /* WatchpointLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WatchpointLocation.cpp; path = source/Breakpoint/WatchpointLocation.cpp; sourceTree = "<group>"; };
+ 26BC7E2910F1B84700F91463 /* CommandObjectAdd.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectAdd.cpp; path = source/Commands/CommandObjectAdd.cpp; sourceTree = "<group>"; };
+ 26BC7E2A10F1B84700F91463 /* CommandObjectAlias.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectAlias.cpp; path = source/Commands/CommandObjectAlias.cpp; sourceTree = "<group>"; };
+ 26BC7E2B10F1B84700F91463 /* CommandObjectAppend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectAppend.cpp; path = source/Commands/CommandObjectAppend.cpp; sourceTree = "<group>"; };
+ 26BC7E2D10F1B84700F91463 /* CommandObjectBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectBreakpoint.cpp; path = source/Commands/CommandObjectBreakpoint.cpp; sourceTree = "<group>"; };
+ 26BC7E2F10F1B84700F91463 /* CommandObjectDelete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectDelete.cpp; path = source/Commands/CommandObjectDelete.cpp; sourceTree = "<group>"; };
+ 26BC7E3010F1B84700F91463 /* CommandObjectDisassemble.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectDisassemble.cpp; path = source/Commands/CommandObjectDisassemble.cpp; sourceTree = "<group>"; };
+ 26BC7E3110F1B84700F91463 /* CommandObjectExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectExpression.cpp; path = source/Commands/CommandObjectExpression.cpp; sourceTree = "<group>"; };
+ 26BC7E3210F1B84700F91463 /* CommandObjectFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectFile.cpp; path = source/Commands/CommandObjectFile.cpp; sourceTree = "<group>"; };
+ 26BC7E3310F1B84700F91463 /* CommandObjectHelp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectHelp.cpp; path = source/Commands/CommandObjectHelp.cpp; sourceTree = "<group>"; };
+ 26BC7E3410F1B84700F91463 /* CommandObjectImage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectImage.cpp; path = source/Commands/CommandObjectImage.cpp; sourceTree = "<group>"; };
+ 26BC7E3510F1B84700F91463 /* CommandObjectInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectInfo.cpp; path = source/Commands/CommandObjectInfo.cpp; sourceTree = "<group>"; };
+ 26BC7E3610F1B84700F91463 /* CommandObjectMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectMemory.cpp; path = source/Commands/CommandObjectMemory.cpp; sourceTree = "<group>"; };
+ 26BC7E3810F1B84700F91463 /* CommandObjectProcess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectProcess.cpp; path = source/Commands/CommandObjectProcess.cpp; sourceTree = "<group>"; };
+ 26BC7E3910F1B84700F91463 /* CommandObjectQuit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectQuit.cpp; path = source/Commands/CommandObjectQuit.cpp; sourceTree = "<group>"; };
+ 26BC7E3B10F1B84700F91463 /* CommandObjectRegister.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectRegister.cpp; path = source/Commands/CommandObjectRegister.cpp; sourceTree = "<group>"; };
+ 26BC7E3C10F1B84700F91463 /* CommandObjectRemove.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectRemove.cpp; path = source/Commands/CommandObjectRemove.cpp; sourceTree = "<group>"; };
+ 26BC7E3D10F1B84700F91463 /* CommandObjectScript.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectScript.cpp; path = source/Commands/CommandObjectScript.cpp; sourceTree = "<group>"; };
+ 26BC7E3E10F1B84700F91463 /* CommandObjectSelect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectSelect.cpp; path = source/Commands/CommandObjectSelect.cpp; sourceTree = "<group>"; };
+ 26BC7E3F10F1B84700F91463 /* CommandObjectSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectSet.cpp; path = source/Commands/CommandObjectSet.cpp; sourceTree = "<group>"; };
+ 26BC7E4010F1B84700F91463 /* CommandObjectSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectSettings.cpp; path = source/Commands/CommandObjectSettings.cpp; sourceTree = "<group>"; };
+ 26BC7E4110F1B84700F91463 /* CommandObjectShow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectShow.cpp; path = source/Commands/CommandObjectShow.cpp; sourceTree = "<group>"; };
+ 26BC7E4210F1B84700F91463 /* CommandObjectSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectSource.cpp; path = source/Commands/CommandObjectSource.cpp; sourceTree = "<group>"; };
+ 26BC7E4310F1B84700F91463 /* CommandObjectSourceFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectSourceFile.cpp; path = source/Commands/CommandObjectSourceFile.cpp; sourceTree = "<group>"; };
+ 26BC7E4410F1B84700F91463 /* CommandObjectStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectStatus.cpp; path = source/Commands/CommandObjectStatus.cpp; sourceTree = "<group>"; };
+ 26BC7E4510F1B84700F91463 /* CommandObjectSyntax.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectSyntax.cpp; path = source/Commands/CommandObjectSyntax.cpp; sourceTree = "<group>"; };
+ 26BC7E4610F1B84700F91463 /* CommandObjectThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectThread.cpp; path = source/Commands/CommandObjectThread.cpp; sourceTree = "<group>"; };
+ 26BC7E4710F1B84700F91463 /* CommandObjectTranslate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectTranslate.cpp; path = source/Commands/CommandObjectTranslate.cpp; sourceTree = "<group>"; };
+ 26BC7E4810F1B84700F91463 /* CommandObjectVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectVariable.cpp; path = source/Commands/CommandObjectVariable.cpp; sourceTree = "<group>"; };
+ 26BC7E6910F1B85900F91463 /* Address.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Address.cpp; path = source/Core/Address.cpp; sourceTree = "<group>"; };
+ 26BC7E6A10F1B85900F91463 /* AddressRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AddressRange.cpp; path = source/Core/AddressRange.cpp; sourceTree = "<group>"; };
+ 26BC7E6B10F1B85900F91463 /* ArchSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ArchSpec.cpp; path = source/Core/ArchSpec.cpp; sourceTree = "<group>"; };
+ 26BC7E6C10F1B85900F91463 /* Args.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Args.cpp; path = source/Core/Args.cpp; sourceTree = "<group>"; };
+ 26BC7E6D10F1B85900F91463 /* Broadcaster.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Broadcaster.cpp; path = source/Core/Broadcaster.cpp; sourceTree = "<group>"; };
+ 26BC7E6E10F1B85900F91463 /* Communication.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Communication.cpp; path = source/Core/Communication.cpp; sourceTree = "<group>"; };
+ 26BC7E6F10F1B85900F91463 /* Connection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Connection.cpp; path = source/Core/Connection.cpp; sourceTree = "<group>"; };
+ 26BC7E7010F1B85900F91463 /* ConnectionFileDescriptor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ConnectionFileDescriptor.cpp; path = source/Core/ConnectionFileDescriptor.cpp; sourceTree = "<group>"; };
+ 26BC7E7110F1B85900F91463 /* DataExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DataExtractor.cpp; path = source/Core/DataExtractor.cpp; sourceTree = "<group>"; };
+ 26BC7E7210F1B85900F91463 /* DataBufferHeap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DataBufferHeap.cpp; path = source/Core/DataBufferHeap.cpp; sourceTree = "<group>"; };
+ 26BC7E7310F1B85900F91463 /* DataBufferMemoryMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DataBufferMemoryMap.cpp; path = source/Core/DataBufferMemoryMap.cpp; sourceTree = "<group>"; };
+ 26BC7E7410F1B85900F91463 /* lldb.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = lldb.cpp; path = source/lldb.cpp; sourceTree = "<group>"; };
+ 26BC7E7510F1B85900F91463 /* lldb-log.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "lldb-log.cpp"; path = "source/lldb-log.cpp"; sourceTree = "<group>"; };
+ 26BC7E7610F1B85900F91463 /* Disassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Disassembler.cpp; path = source/Core/Disassembler.cpp; sourceTree = "<group>"; };
+ 26BC7E7710F1B85900F91463 /* DynamicLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DynamicLoader.cpp; path = source/Core/DynamicLoader.cpp; sourceTree = "<group>"; };
+ 26BC7E7810F1B85900F91463 /* Error.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Error.cpp; path = source/Core/Error.cpp; sourceTree = "<group>"; };
+ 26BC7E7910F1B85900F91463 /* Event.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Event.cpp; path = source/Core/Event.cpp; sourceTree = "<group>"; };
+ 26BC7E7A10F1B85900F91463 /* FileSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FileSpec.cpp; path = source/Core/FileSpec.cpp; sourceTree = "<group>"; };
+ 26BC7E7B10F1B85900F91463 /* FileSpecList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FileSpecList.cpp; path = source/Core/FileSpecList.cpp; sourceTree = "<group>"; };
+ 26BC7E7C10F1B85900F91463 /* Flags.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Flags.cpp; path = source/Core/Flags.cpp; sourceTree = "<group>"; };
+ 26BC7E7D10F1B85900F91463 /* Language.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Language.cpp; path = source/Core/Language.cpp; sourceTree = "<group>"; };
+ 26BC7E7E10F1B85900F91463 /* Listener.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Listener.cpp; path = source/Core/Listener.cpp; sourceTree = "<group>"; };
+ 26BC7E7F10F1B85900F91463 /* Log.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Log.cpp; path = source/Core/Log.cpp; sourceTree = "<group>"; };
+ 26BC7E8010F1B85900F91463 /* Mangled.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mangled.cpp; path = source/Core/Mangled.cpp; sourceTree = "<group>"; };
+ 26BC7E8110F1B85900F91463 /* Module.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Module.cpp; path = source/Core/Module.cpp; sourceTree = "<group>"; };
+ 26BC7E8210F1B85900F91463 /* ModuleChild.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleChild.cpp; path = source/Core/ModuleChild.cpp; sourceTree = "<group>"; };
+ 26BC7E8310F1B85900F91463 /* ModuleList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleList.cpp; path = source/Core/ModuleList.cpp; sourceTree = "<group>"; };
+ 26BC7E8610F1B85900F91463 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = source/Core/Options.cpp; sourceTree = "<group>"; };
+ 26BC7E8A10F1B85900F91463 /* PluginManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PluginManager.cpp; path = source/Core/PluginManager.cpp; sourceTree = "<group>"; };
+ 26BC7E8C10F1B85900F91463 /* RegularExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegularExpression.cpp; path = source/Core/RegularExpression.cpp; sourceTree = "<group>"; };
+ 26BC7E8D10F1B85900F91463 /* Scalar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Scalar.cpp; path = source/Core/Scalar.cpp; sourceTree = "<group>"; };
+ 26BC7E8E10F1B85900F91463 /* Section.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Section.cpp; path = source/Core/Section.cpp; sourceTree = "<group>"; };
+ 26BC7E8F10F1B85900F91463 /* SourceManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SourceManager.cpp; path = source/Core/SourceManager.cpp; sourceTree = "<group>"; };
+ 26BC7E9010F1B85900F91463 /* State.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = State.cpp; path = source/Core/State.cpp; sourceTree = "<group>"; };
+ 26BC7E9110F1B85900F91463 /* Stream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Stream.cpp; path = source/Core/Stream.cpp; sourceTree = "<group>"; };
+ 26BC7E9210F1B85900F91463 /* StreamFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StreamFile.cpp; path = source/Core/StreamFile.cpp; sourceTree = "<group>"; };
+ 26BC7E9310F1B85900F91463 /* StreamString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StreamString.cpp; path = source/Core/StreamString.cpp; sourceTree = "<group>"; };
+ 26BC7E9410F1B85900F91463 /* ConstString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ConstString.cpp; path = source/Core/ConstString.cpp; sourceTree = "<group>"; };
+ 26BC7E9610F1B85900F91463 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Timer.cpp; path = source/Core/Timer.cpp; sourceTree = "<group>"; };
+ 26BC7E9710F1B85900F91463 /* TTYState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TTYState.cpp; path = source/Core/TTYState.cpp; sourceTree = "<group>"; };
+ 26BC7E9810F1B85900F91463 /* UserID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UserID.cpp; path = source/Core/UserID.cpp; sourceTree = "<group>"; };
+ 26BC7E9910F1B85900F91463 /* Value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Value.cpp; path = source/Core/Value.cpp; sourceTree = "<group>"; };
+ 26BC7E9A10F1B85900F91463 /* ValueObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObject.cpp; path = source/Core/ValueObject.cpp; sourceTree = "<group>"; };
+ 26BC7E9B10F1B85900F91463 /* ValueObjectChild.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectChild.cpp; path = source/Core/ValueObjectChild.cpp; sourceTree = "<group>"; };
+ 26BC7E9C10F1B85900F91463 /* ValueObjectList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectList.cpp; path = source/Core/ValueObjectList.cpp; sourceTree = "<group>"; };
+ 26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectVariable.cpp; path = source/Core/ValueObjectVariable.cpp; sourceTree = "<group>"; };
+ 26BC7E9E10F1B85900F91463 /* VMRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VMRange.cpp; path = source/Core/VMRange.cpp; sourceTree = "<group>"; };
+ 26BC7ED510F1B86700F91463 /* ClangExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangExpression.cpp; path = source/Expression/ClangExpression.cpp; sourceTree = "<group>"; };
+ 26BC7ED610F1B86700F91463 /* ClangExpressionVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangExpressionVariable.cpp; path = source/Expression/ClangExpressionVariable.cpp; sourceTree = "<group>"; };
+ 26BC7ED710F1B86700F91463 /* ClangStmtVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangStmtVisitor.cpp; path = source/Expression/ClangStmtVisitor.cpp; sourceTree = "<group>"; };
+ 26BC7ED810F1B86700F91463 /* DWARFExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DWARFExpression.cpp; path = source/Expression/DWARFExpression.cpp; sourceTree = "<group>"; };
+ 26BC7EE710F1B88F00F91463 /* Condition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Condition.cpp; path = source/Host/macosx/Condition.cpp; sourceTree = "<group>"; };
+ 26BC7EE810F1B88F00F91463 /* Host.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Host.mm; path = source/Host/macosx/Host.mm; sourceTree = "<group>"; };
+ 26BC7EE910F1B88F00F91463 /* Mutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mutex.cpp; path = source/Host/macosx/Mutex.cpp; sourceTree = "<group>"; };
+ 26BC7EED10F1B8AD00F91463 /* CFCBundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CFCBundle.cpp; path = source/Host/macosx/cfcpp/CFCBundle.cpp; sourceTree = "<group>"; };
+ 26BC7EEE10F1B8AD00F91463 /* CFCBundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFCBundle.h; path = source/Host/macosx/cfcpp/CFCBundle.h; sourceTree = "<group>"; };
+ 26BC7EEF10F1B8AD00F91463 /* CFCData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CFCData.cpp; path = source/Host/macosx/cfcpp/CFCData.cpp; sourceTree = "<group>"; };
+ 26BC7EF010F1B8AD00F91463 /* CFCData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFCData.h; path = source/Host/macosx/cfcpp/CFCData.h; sourceTree = "<group>"; };
+ 26BC7EF110F1B8AD00F91463 /* CFCMutableArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CFCMutableArray.cpp; path = source/Host/macosx/cfcpp/CFCMutableArray.cpp; sourceTree = "<group>"; };
+ 26BC7EF210F1B8AD00F91463 /* CFCMutableArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFCMutableArray.h; path = source/Host/macosx/cfcpp/CFCMutableArray.h; sourceTree = "<group>"; };
+ 26BC7EF310F1B8AD00F91463 /* CFCMutableDictionary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CFCMutableDictionary.cpp; path = source/Host/macosx/cfcpp/CFCMutableDictionary.cpp; sourceTree = "<group>"; };
+ 26BC7EF410F1B8AD00F91463 /* CFCMutableDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFCMutableDictionary.h; path = source/Host/macosx/cfcpp/CFCMutableDictionary.h; sourceTree = "<group>"; };
+ 26BC7EF510F1B8AD00F91463 /* CFCMutableSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CFCMutableSet.cpp; path = source/Host/macosx/cfcpp/CFCMutableSet.cpp; sourceTree = "<group>"; };
+ 26BC7EF610F1B8AD00F91463 /* CFCMutableSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFCMutableSet.h; path = source/Host/macosx/cfcpp/CFCMutableSet.h; sourceTree = "<group>"; };
+ 26BC7EF710F1B8AD00F91463 /* CFCReleaser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFCReleaser.h; path = source/Host/macosx/cfcpp/CFCReleaser.h; sourceTree = "<group>"; };
+ 26BC7EF810F1B8AD00F91463 /* CFCString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CFCString.cpp; path = source/Host/macosx/cfcpp/CFCString.cpp; sourceTree = "<group>"; };
+ 26BC7EF910F1B8AD00F91463 /* CFCString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFCString.h; path = source/Host/macosx/cfcpp/CFCString.h; sourceTree = "<group>"; };
+ 26BC7F0710F1B8DD00F91463 /* CommandContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandContext.cpp; path = source/Interpreter/CommandContext.cpp; sourceTree = "<group>"; };
+ 26BC7F0810F1B8DD00F91463 /* CommandInterpreter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandInterpreter.cpp; path = source/Interpreter/CommandInterpreter.cpp; sourceTree = "<group>"; };
+ 26BC7F0910F1B8DD00F91463 /* CommandObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObject.cpp; path = source/Interpreter/CommandObject.cpp; sourceTree = "<group>"; };
+ 26BC7F0A10F1B8DD00F91463 /* CommandReturnObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandReturnObject.cpp; path = source/Interpreter/CommandReturnObject.cpp; sourceTree = "<group>"; };
+ 26BC7F0B10F1B8DD00F91463 /* StateVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StateVariable.cpp; path = source/Interpreter/StateVariable.cpp; sourceTree = "<group>"; };
+ 26BC7F0C10F1B8DD00F91463 /* ScriptInterpreterPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScriptInterpreterPython.cpp; path = source/Interpreter/ScriptInterpreterPython.cpp; sourceTree = "<group>"; };
+ 26BC7F1310F1B8EC00F91463 /* Block.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Block.cpp; path = source/Symbol/Block.cpp; sourceTree = "<group>"; };
+ 26BC7F1410F1B8EC00F91463 /* ClangASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangASTContext.cpp; path = source/Symbol/ClangASTContext.cpp; sourceTree = "<group>"; };
+ 26BC7F1510F1B8EC00F91463 /* CompileUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompileUnit.cpp; path = source/Symbol/CompileUnit.cpp; sourceTree = "<group>"; };
+ 26BC7F1610F1B8EC00F91463 /* Declaration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Declaration.cpp; path = source/Symbol/Declaration.cpp; sourceTree = "<group>"; };
+ 26BC7F1710F1B8EC00F91463 /* DWARFCallFrameInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DWARFCallFrameInfo.cpp; path = source/Symbol/DWARFCallFrameInfo.cpp; sourceTree = "<group>"; };
+ 26BC7F1810F1B8EC00F91463 /* Function.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Function.cpp; path = source/Symbol/Function.cpp; sourceTree = "<group>"; };
+ 26BC7F1910F1B8EC00F91463 /* LineEntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LineEntry.cpp; path = source/Symbol/LineEntry.cpp; sourceTree = "<group>"; };
+ 26BC7F1A10F1B8EC00F91463 /* LineTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LineTable.cpp; path = source/Symbol/LineTable.cpp; sourceTree = "<group>"; };
+ 26BC7F1B10F1B8EC00F91463 /* Symbol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Symbol.cpp; path = source/Symbol/Symbol.cpp; sourceTree = "<group>"; };
+ 26BC7F1C10F1B8EC00F91463 /* SymbolContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolContext.cpp; path = source/Symbol/SymbolContext.cpp; sourceTree = "<group>"; };
+ 26BC7F1D10F1B8EC00F91463 /* SymbolFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolFile.cpp; path = source/Symbol/SymbolFile.cpp; sourceTree = "<group>"; };
+ 26BC7F1E10F1B8EC00F91463 /* SymbolVendor.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = SymbolVendor.mm; path = source/Symbol/SymbolVendor.mm; sourceTree = "<group>"; };
+ 26BC7F1F10F1B8EC00F91463 /* Symtab.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Symtab.cpp; path = source/Symbol/Symtab.cpp; sourceTree = "<group>"; };
+ 26BC7F2010F1B8EC00F91463 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Type.cpp; path = source/Symbol/Type.cpp; sourceTree = "<group>"; };
+ 26BC7F2110F1B8EC00F91463 /* TypeList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeList.cpp; path = source/Symbol/TypeList.cpp; sourceTree = "<group>"; };
+ 26BC7F2210F1B8EC00F91463 /* Variable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Variable.cpp; path = source/Symbol/Variable.cpp; sourceTree = "<group>"; };
+ 26BC7F2310F1B8EC00F91463 /* VariableList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VariableList.cpp; path = source/Symbol/VariableList.cpp; sourceTree = "<group>"; };
+ 26BC7F3510F1B90C00F91463 /* ExecutionContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExecutionContext.cpp; path = source/Target/ExecutionContext.cpp; sourceTree = "<group>"; };
+ 26BC7F3610F1B90C00F91463 /* Process.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Process.cpp; path = source/Target/Process.cpp; sourceTree = "<group>"; };
+ 26BC7F3710F1B90C00F91463 /* RegisterContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterContext.cpp; path = source/Target/RegisterContext.cpp; sourceTree = "<group>"; };
+ 26BC7F3810F1B90C00F91463 /* StackFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StackFrame.cpp; path = source/Target/StackFrame.cpp; sourceTree = "<group>"; };
+ 26BC7F3910F1B90C00F91463 /* StackFrameList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StackFrameList.cpp; path = source/Target/StackFrameList.cpp; sourceTree = "<group>"; };
+ 26BC7F3A10F1B90C00F91463 /* StackID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StackID.cpp; path = source/Target/StackID.cpp; sourceTree = "<group>"; };
+ 26BC7F3B10F1B90C00F91463 /* Target.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Target.cpp; path = source/Target/Target.cpp; sourceTree = "<group>"; };
+ 26BC7F3C10F1B90C00F91463 /* TargetList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TargetList.cpp; path = source/Target/TargetList.cpp; sourceTree = "<group>"; };
+ 26BC7F3D10F1B90C00F91463 /* Thread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Thread.cpp; path = source/Target/Thread.cpp; sourceTree = "<group>"; };
+ 26BC7F3E10F1B90C00F91463 /* ThreadList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadList.cpp; path = source/Target/ThreadList.cpp; sourceTree = "<group>"; };
+ 26BC7F3F10F1B90C00F91463 /* ThreadPlan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlan.cpp; path = source/Target/ThreadPlan.cpp; sourceTree = "<group>"; };
+ 26BC7F4C10F1BC1A00F91463 /* ObjectFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ObjectFile.cpp; path = source/Symbol/ObjectFile.cpp; sourceTree = "<group>"; };
+ 26C81CA411335651004BDC5A /* UUID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UUID.h; path = include/lldb/Core/UUID.h; sourceTree = "<group>"; };
+ 26C81CA511335651004BDC5A /* UUID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UUID.cpp; path = source/Core/UUID.cpp; sourceTree = "<group>"; };
+ 26C9DF03113C5B93006B0F94 /* lldb */ = {isa = PBXFileReference; lastKnownFileType = folder; name = lldb; path = include/lldb; sourceTree = "<group>"; };
+ 26D0DD5010FE554D00271C65 /* BreakpointResolverAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointResolverAddress.h; path = include/lldb/Breakpoint/BreakpointResolverAddress.h; sourceTree = "<group>"; };
+ 26D0DD5110FE554D00271C65 /* BreakpointResolverFileLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointResolverFileLine.h; path = include/lldb/Breakpoint/BreakpointResolverFileLine.h; sourceTree = "<group>"; };
+ 26D0DD5210FE554D00271C65 /* BreakpointResolverName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointResolverName.h; path = include/lldb/Breakpoint/BreakpointResolverName.h; sourceTree = "<group>"; };
+ 26D0DD5310FE555900271C65 /* BreakpointResolverAddress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointResolverAddress.cpp; path = source/Breakpoint/BreakpointResolverAddress.cpp; sourceTree = "<group>"; };
+ 26D0DD5410FE555900271C65 /* BreakpointResolverFileLine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointResolverFileLine.cpp; path = source/Breakpoint/BreakpointResolverFileLine.cpp; sourceTree = "<group>"; };
+ 26D0DD5510FE555900271C65 /* BreakpointResolverName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointResolverName.cpp; path = source/Breakpoint/BreakpointResolverName.cpp; sourceTree = "<group>"; };
+ 26DAFD9711529BC7005A394E /* ExecutionContextScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExecutionContextScope.h; path = include/lldb/Target/ExecutionContextScope.h; sourceTree = "<group>"; };
+ 26DE1E6911616C2E00A093E2 /* lldb-forward-rtti.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-forward-rtti.h"; path = "include/lldb/lldb-forward-rtti.h"; sourceTree = "<group>"; };
+ 26DE1E6A11616C2E00A093E2 /* lldb-forward.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-forward.h"; path = "include/lldb/lldb-forward.h"; sourceTree = "<group>"; };
+ 26DE204011618AB900A093E2 /* SBSymbolContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBSymbolContext.h; path = include/lldb/API/SBSymbolContext.h; sourceTree = "<group>"; };
+ 26DE204211618ACA00A093E2 /* SBAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBAddress.h; path = include/lldb/API/SBAddress.h; sourceTree = "<group>"; };
+ 26DE204411618ADA00A093E2 /* SBAddress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBAddress.cpp; path = source/API/SBAddress.cpp; sourceTree = "<group>"; };
+ 26DE204611618AED00A093E2 /* SBSymbolContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBSymbolContext.cpp; path = source/API/SBSymbolContext.cpp; sourceTree = "<group>"; };
+ 26DE204C11618E7A00A093E2 /* SBModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBModule.cpp; path = source/API/SBModule.cpp; sourceTree = "<group>"; };
+ 26DE204E11618E9800A093E2 /* SBModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBModule.h; path = include/lldb/API/SBModule.h; sourceTree = "<group>"; };
+ 26DE205211618FAC00A093E2 /* SBFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBFunction.h; path = include/lldb/API/SBFunction.h; sourceTree = "<group>"; };
+ 26DE205411618FB800A093E2 /* SBCompileUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBCompileUnit.h; path = include/lldb/API/SBCompileUnit.h; sourceTree = "<group>"; };
+ 26DE205611618FC500A093E2 /* SBBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBBlock.h; path = include/lldb/API/SBBlock.h; sourceTree = "<group>"; };
+ 26DE205811618FE700A093E2 /* SBLineEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBLineEntry.h; path = include/lldb/API/SBLineEntry.h; sourceTree = "<group>"; };
+ 26DE205A11618FF600A093E2 /* SBSymbol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBSymbol.h; path = include/lldb/API/SBSymbol.h; sourceTree = "<group>"; };
+ 26DE205C1161901400A093E2 /* SBFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBFunction.cpp; path = source/API/SBFunction.cpp; sourceTree = "<group>"; };
+ 26DE205E1161901B00A093E2 /* SBCompileUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBCompileUnit.cpp; path = source/API/SBCompileUnit.cpp; sourceTree = "<group>"; };
+ 26DE20601161902600A093E2 /* SBBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBBlock.cpp; path = source/API/SBBlock.cpp; sourceTree = "<group>"; };
+ 26DE20621161904200A093E2 /* SBLineEntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBLineEntry.cpp; path = source/API/SBLineEntry.cpp; sourceTree = "<group>"; };
+ 26DE20641161904E00A093E2 /* SBSymbol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBSymbol.cpp; path = source/API/SBSymbol.cpp; sourceTree = "<group>"; };
+ 26DFBC50113B48D600DD817F /* CommandObjectCrossref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectCrossref.h; path = include/lldb/Interpreter/CommandObjectCrossref.h; sourceTree = "<group>"; };
+ 26DFBC51113B48D600DD817F /* CommandObjectMultiword.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectMultiword.h; path = include/lldb/Interpreter/CommandObjectMultiword.h; sourceTree = "<group>"; };
+ 26DFBC52113B48D600DD817F /* CommandObjectRegexCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectRegexCommand.h; path = include/lldb/Interpreter/CommandObjectRegexCommand.h; sourceTree = "<group>"; };
+ 26DFBC57113B48F300DD817F /* CommandObjectCrossref.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectCrossref.cpp; path = source/Interpreter/CommandObjectCrossref.cpp; sourceTree = "<group>"; };
+ 26DFBC58113B48F300DD817F /* CommandObjectMultiword.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectMultiword.cpp; path = source/Interpreter/CommandObjectMultiword.cpp; sourceTree = "<group>"; };
+ 26DFBC59113B48F300DD817F /* CommandObjectRegexCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectRegexCommand.cpp; path = source/Interpreter/CommandObjectRegexCommand.cpp; sourceTree = "<group>"; };
+ 26E3EEBD11A9870400FBADB6 /* Unwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Unwind.h; path = include/lldb/Target/Unwind.h; sourceTree = "<group>"; };
+ 26E3EEBE11A98A1900FBADB6 /* UnwindLibUnwind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindLibUnwind.cpp; path = Utility/UnwindLibUnwind.cpp; sourceTree = "<group>"; };
+ 26E3EEBF11A98A1900FBADB6 /* UnwindLibUnwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UnwindLibUnwind.h; path = Utility/UnwindLibUnwind.h; sourceTree = "<group>"; };
+ 26E3EEE311A9901300FBADB6 /* UnwindMacOSXFrameBackchain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindMacOSXFrameBackchain.cpp; path = Utility/UnwindMacOSXFrameBackchain.cpp; sourceTree = "<group>"; };
+ 26E3EEE411A9901300FBADB6 /* UnwindMacOSXFrameBackchain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UnwindMacOSXFrameBackchain.h; path = Utility/UnwindMacOSXFrameBackchain.h; sourceTree = "<group>"; };
+ 26E3EEF711A994E800FBADB6 /* RegisterContextMacOSXFrameBackchain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterContextMacOSXFrameBackchain.cpp; path = Utility/RegisterContextMacOSXFrameBackchain.cpp; sourceTree = "<group>"; };
+ 26E3EEF811A994E800FBADB6 /* RegisterContextMacOSXFrameBackchain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextMacOSXFrameBackchain.h; path = Utility/RegisterContextMacOSXFrameBackchain.h; sourceTree = "<group>"; };
+ 26F5C26A10F3D9A4009D5894 /* lldb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lldb; sourceTree = BUILT_PRODUCTS_DIR; };
+ 26F5C27210F3D9E4009D5894 /* lldb-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "lldb-Info.plist"; path = "tools/driver/lldb-Info.plist"; sourceTree = "<group>"; };
+ 26F5C27310F3D9E4009D5894 /* Driver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Driver.cpp; path = tools/driver/Driver.cpp; sourceTree = "<group>"; };
+ 26F5C27410F3D9E4009D5894 /* Driver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Driver.h; path = tools/driver/Driver.h; sourceTree = "<group>"; };
+ 26F5C27510F3D9E4009D5894 /* IOChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IOChannel.cpp; path = tools/driver/IOChannel.cpp; sourceTree = "<group>"; };
+ 26F5C27610F3D9E4009D5894 /* IOChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IOChannel.h; path = tools/driver/IOChannel.h; sourceTree = "<group>"; };
+ 26F5C32410F3DF23009D5894 /* libpython2.6.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpython2.6.dylib; path = /usr/lib/libpython2.6.dylib; sourceTree = "<absolute>"; };
+ 26F5C32A10F3DFDD009D5894 /* libedit.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libedit.dylib; path = /usr/lib/libedit.dylib; sourceTree = "<absolute>"; };
+ 26F5C32B10F3DFDD009D5894 /* libtermcap.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libtermcap.dylib; path = /usr/lib/libtermcap.dylib; sourceTree = "<absolute>"; };
+ 26F5C37410F3F61B009D5894 /* libobjc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libobjc.dylib; path = /usr/lib/libobjc.dylib; sourceTree = "<absolute>"; };
+ 26F5C39010F3FA26009D5894 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+ 26F996A7119B79C300412154 /* ARM_DWARF_Registers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ARM_DWARF_Registers.h; path = source/Utility/ARM_DWARF_Registers.h; sourceTree = "<group>"; };
+ 26F996A8119B79C300412154 /* ARM_GCC_Registers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ARM_GCC_Registers.h; path = source/Utility/ARM_GCC_Registers.h; sourceTree = "<group>"; };
+ 26FE25221146CADE00F4085A /* GDBRemoteCommunication.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GDBRemoteCommunication.cpp; path = "source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp"; sourceTree = "<group>"; };
+ 26FE25231146CADE00F4085A /* GDBRemoteCommunication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GDBRemoteCommunication.h; path = "source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h"; sourceTree = "<group>"; };
+ 493C63F01189203300914D5E /* ABISysV_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ABISysV_x86_64.h; path = "ABI/SysV-x86_64/ABISysV_x86_64.h"; sourceTree = "<group>"; };
+ 493C63F11189203300914D5E /* ABISysV_x86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ABISysV_x86_64.cpp; path = "ABI/SysV-x86_64/ABISysV_x86_64.cpp"; sourceTree = "<group>"; };
+ 495BBACB119A0DBE00418BEA /* PathMappingList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PathMappingList.cpp; path = source/Target/PathMappingList.cpp; sourceTree = "<group>"; };
+ 495BBACF119A0DE700418BEA /* PathMappingList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PathMappingList.h; path = include/lldb/Target/PathMappingList.h; sourceTree = "<group>"; };
+ 497650CE11A21BEE008DDB57 /* ABIMacOSX_i386.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ABIMacOSX_i386.cpp; path = "ABI/MacOSX-i386/ABIMacOSX_i386.cpp"; sourceTree = "<group>"; };
+ 497650CF11A21BEE008DDB57 /* ABIMacOSX_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ABIMacOSX_i386.h; path = "ABI/MacOSX-i386/ABIMacOSX_i386.h"; sourceTree = "<group>"; };
+ 497E7B331188ED300065CCA1 /* ABI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ABI.h; path = include/lldb/Target/ABI.h; sourceTree = "<group>"; };
+ 497E7B9D1188F6690065CCA1 /* ABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ABI.cpp; path = source/Target/ABI.cpp; sourceTree = "<group>"; };
+ 499F381E11A5B3F300F5CE02 /* CommandObjectArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectArgs.h; path = source/Commands/CommandObjectArgs.h; sourceTree = "<group>"; };
+ 499F381F11A5B3F300F5CE02 /* CommandObjectArgs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectArgs.cpp; path = source/Commands/CommandObjectArgs.cpp; sourceTree = "<group>"; };
+ 49BF48DC11ADF356008863BD /* ObjCObjectPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ObjCObjectPrinter.cpp; path = source/Target/ObjCObjectPrinter.cpp; sourceTree = "<group>"; };
+ 49BF48E011ADF37D008863BD /* ObjCObjectPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjCObjectPrinter.h; path = include/lldb/Target/ObjCObjectPrinter.h; sourceTree = "<group>"; };
+ 49D7072611B5AD03001AD875 /* ClangASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangASTSource.h; path = include/lldb/Expression/ClangASTSource.h; sourceTree = "<group>"; };
+ 49D7072811B5AD11001AD875 /* ClangASTSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangASTSource.cpp; path = source/Expression/ClangASTSource.cpp; sourceTree = "<group>"; };
+ 49EC3E98118F90AC00B1265E /* ThreadPlanCallFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanCallFunction.cpp; path = source/Target/ThreadPlanCallFunction.cpp; sourceTree = "<group>"; };
+ 49EC3E9C118F90D400B1265E /* ThreadPlanCallFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanCallFunction.h; path = include/lldb/Target/ThreadPlanCallFunction.h; sourceTree = "<group>"; };
+ 49F1A74511B3388F003ED505 /* ClangExpressionDeclMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangExpressionDeclMap.cpp; path = source/Expression/ClangExpressionDeclMap.cpp; sourceTree = "<group>"; };
+ 49F1A74911B338AE003ED505 /* ClangExpressionDeclMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangExpressionDeclMap.h; path = include/lldb/Expression/ClangExpressionDeclMap.h; sourceTree = "<group>"; };
+ 4C00986F11500B4300F316B0 /* UnixSignals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UnixSignals.h; path = include/lldb/Target/UnixSignals.h; sourceTree = "<group>"; };
+ 4C00987011500B4300F316B0 /* UnixSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnixSignals.cpp; path = source/Target/UnixSignals.cpp; sourceTree = "<group>"; };
+ 4C09CB73116BD98B00C7A725 /* CommandCompletions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandCompletions.h; path = include/lldb/Interpreter/CommandCompletions.h; sourceTree = "<group>"; };
+ 4C09CB74116BD98B00C7A725 /* CommandCompletions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandCompletions.cpp; path = source/Interpreter/CommandCompletions.cpp; sourceTree = "<group>"; };
+ 4C43DEF9110641F300E55CBF /* ThreadPlanShouldStopHere.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanShouldStopHere.h; path = include/lldb/Target/ThreadPlanShouldStopHere.h; sourceTree = "<group>"; };
+ 4C43DEFA110641F300E55CBF /* ThreadPlanShouldStopHere.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanShouldStopHere.cpp; path = source/Target/ThreadPlanShouldStopHere.cpp; sourceTree = "<group>"; };
+ 4C43DF8511069BFD00E55CBF /* ThreadPlanStepInRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepInRange.h; path = include/lldb/Target/ThreadPlanStepInRange.h; sourceTree = "<group>"; };
+ 4C43DF8611069BFD00E55CBF /* ThreadPlanStepOverRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepOverRange.h; path = include/lldb/Target/ThreadPlanStepOverRange.h; sourceTree = "<group>"; };
+ 4C43DF8911069C3200E55CBF /* ThreadPlanStepInRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanStepInRange.cpp; path = source/Target/ThreadPlanStepInRange.cpp; sourceTree = "<group>"; };
+ 4C43DF8A11069C3200E55CBF /* ThreadPlanStepOverRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanStepOverRange.cpp; path = source/Target/ThreadPlanStepOverRange.cpp; sourceTree = "<group>"; };
+ 4C51FF1511A4C485007C962F /* ObjCTrampolineHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjCTrampolineHandler.h; sourceTree = "<group>"; };
+ 4C51FF1611A4C486007C962F /* ObjCTrampolineHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjCTrampolineHandler.cpp; sourceTree = "<group>"; };
+ 4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangFunction.cpp; path = source/Expression/ClangFunction.cpp; sourceTree = "<group>"; };
+ 4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecordingMemoryManager.cpp; path = source/Expression/RecordingMemoryManager.cpp; sourceTree = "<group>"; };
+ 4C98D3E0118FB98F00E575D0 /* ClangFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangFunction.h; path = include/lldb/Expression/ClangFunction.h; sourceTree = "<group>"; };
+ 4C98D3E1118FB98F00E575D0 /* RecordingMemoryManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RecordingMemoryManager.h; path = include/lldb/Expression/RecordingMemoryManager.h; sourceTree = "<group>"; };
+ 4C98D3E4118FB9B100E575D0 /* CommandObjectCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectCall.cpp; path = source/Commands/CommandObjectCall.cpp; sourceTree = "<group>"; };
+ 4C98D3E5118FB9B100E575D0 /* CommandObjectCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectCall.h; path = source/Commands/CommandObjectCall.h; sourceTree = "<group>"; };
+ 4CA9637911B6E99A00780E28 /* CommandObjectApropos.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectApropos.cpp; path = source/Commands/CommandObjectApropos.cpp; sourceTree = "<group>"; };
+ 4CA9637A11B6E99A00780E28 /* CommandObjectApropos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectApropos.h; path = source/Commands/CommandObjectApropos.h; sourceTree = "<group>"; };
+ 4CAFCE001101216B00CA63DB /* ThreadPlanRunToAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanRunToAddress.h; path = include/lldb/Target/ThreadPlanRunToAddress.h; sourceTree = "<group>"; };
+ 4CAFCE031101218900CA63DB /* ThreadPlanRunToAddress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanRunToAddress.cpp; path = source/Target/ThreadPlanRunToAddress.cpp; sourceTree = "<group>"; };
+ 4CEDAED311754F5E00E875A6 /* ThreadPlanStepUntil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepUntil.h; path = include/lldb/Target/ThreadPlanStepUntil.h; sourceTree = "<group>"; };
+ 4CEE62FA1145F2130064CF93 /* ProcessGDBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProcessGDBRemote.cpp; path = "source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp"; sourceTree = "<group>"; };
+ 4CEE62FB1145F2130064CF93 /* ProcessGDBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProcessGDBRemote.h; path = "source/Plugins/Process/gdb-remote/ProcessGDBRemote.h"; sourceTree = "<group>"; };
+ 4CEE62FC1145F2130064CF93 /* ProcessGDBRemoteLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProcessGDBRemoteLog.cpp; path = "source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp"; sourceTree = "<group>"; };
+ 4CEE62FD1145F2130064CF93 /* ProcessGDBRemoteLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProcessGDBRemoteLog.h; path = "source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"; sourceTree = "<group>"; };
+ 4CEE62FE1145F2130064CF93 /* ThreadGDBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadGDBRemote.cpp; path = "source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp"; sourceTree = "<group>"; };
+ 4CEE62FF1145F2130064CF93 /* ThreadGDBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadGDBRemote.h; path = "source/Plugins/Process/gdb-remote/ThreadGDBRemote.h"; sourceTree = "<group>"; };
+ 4CF4473D11A8687100EF971E /* ThreadPlanStepThroughObjCTrampoline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadPlanStepThroughObjCTrampoline.h; sourceTree = "<group>"; };
+ 4CF4473E11A8687100EF971E /* ThreadPlanStepThroughObjCTrampoline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadPlanStepThroughObjCTrampoline.cpp; sourceTree = "<group>"; };
+ 9654F79C1197DA1300F72B43 /* MacOSXLibunwindCallbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MacOSXLibunwindCallbacks.cpp; path = Utility/MacOSXLibunwindCallbacks.cpp; sourceTree = "<group>"; };
+ 9654F79D1197DA1300F72B43 /* MacOSXLibunwindCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MacOSXLibunwindCallbacks.h; path = Utility/MacOSXLibunwindCallbacks.h; sourceTree = "<group>"; };
+ 9654F7A11197DA3F00F72B43 /* libunwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libunwind.h; sourceTree = "<group>"; };
+ 9654F7A31197DA3F00F72B43 /* compact_unwind_encoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compact_unwind_encoding.h; sourceTree = "<group>"; };
+ 9654F7A41197DA3F00F72B43 /* unwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unwind.h; sourceTree = "<group>"; };
+ 9654F7A61197DA3F00F72B43 /* AddressSpace.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AddressSpace.hpp; sourceTree = "<group>"; };
+ 9654F7A71197DA3F00F72B43 /* ArchDefaultUnwinder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ArchDefaultUnwinder.hpp; sourceTree = "<group>"; };
+ 9654F7A81197DA3F00F72B43 /* AssemblyInstructions.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AssemblyInstructions.hpp; sourceTree = "<group>"; };
+ 9654F7A91197DA3F00F72B43 /* AssemblyParser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AssemblyParser.hpp; sourceTree = "<group>"; };
+ 9654F7AA1197DA3F00F72B43 /* CompactUnwinder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CompactUnwinder.hpp; sourceTree = "<group>"; };
+ 9654F7AB1197DA3F00F72B43 /* dwarf2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dwarf2.h; sourceTree = "<group>"; };
+ 9654F7AC1197DA3F00F72B43 /* DwarfInstructions.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DwarfInstructions.hpp; sourceTree = "<group>"; };
+ 9654F7AD1197DA3F00F72B43 /* DwarfParser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DwarfParser.hpp; sourceTree = "<group>"; };
+ 9654F7AE1197DA3F00F72B43 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FileAbstraction.hpp; sourceTree = "<group>"; };
+ 9654F7AF1197DA3F00F72B43 /* InternalMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InternalMacros.h; sourceTree = "<group>"; };
+ 9654F7B21197DA3F00F72B43 /* libunwind_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libunwind_priv.h; sourceTree = "<group>"; };
+ 9654F7B31197DA3F00F72B43 /* libuwind.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libuwind.cxx; sourceTree = "<group>"; };
+ 9654F7B41197DA3F00F72B43 /* Registers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Registers.hpp; sourceTree = "<group>"; };
+ 9654F7B51197DA3F00F72B43 /* Registers.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = Registers.s; sourceTree = "<group>"; };
+ 9654F7B61197DA3F00F72B43 /* RemoteDebuggerDummyUnwinder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RemoteDebuggerDummyUnwinder.hpp; sourceTree = "<group>"; };
+ 9654F7B71197DA3F00F72B43 /* RemoteProcInfo.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RemoteProcInfo.hpp; sourceTree = "<group>"; };
+ 9654F7B81197DA3F00F72B43 /* RemoteRegisterMap.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RemoteRegisterMap.hpp; sourceTree = "<group>"; };
+ 9654F7B91197DA3F00F72B43 /* RemoteUnwindProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteUnwindProfile.h; sourceTree = "<group>"; };
+ 9654F7BA1197DA3F00F72B43 /* unw_getcontext.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = unw_getcontext.s; sourceTree = "<group>"; };
+ 9654F7BD1197DA3F00F72B43 /* UnwindCursor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = UnwindCursor.hpp; sourceTree = "<group>"; };
+ 9A19A6A51163BB7E00E0D453 /* SBValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBValue.h; path = include/lldb/API/SBValue.h; sourceTree = "<group>"; };
+ 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBValue.cpp; path = source/API/SBValue.cpp; sourceTree = "<group>"; };
+ 9A2771FB1135A35C00E6ADB6 /* ScriptInterpreterNone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScriptInterpreterNone.h; path = include/lldb/Interpreter/ScriptInterpreterNone.h; sourceTree = "<group>"; };
+ 9A2771FC1135A37500E6ADB6 /* ScriptInterpreterNone.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScriptInterpreterNone.cpp; path = source/Interpreter/ScriptInterpreterNone.cpp; sourceTree = "<group>"; };
+ 9A357582116CFDEE00E8ED2F /* SBValueList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBValueList.h; path = include/lldb/API/SBValueList.h; sourceTree = "<group>"; };
+ 9A35758D116CFE0F00E8ED2F /* SBValueList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBValueList.cpp; path = source/API/SBValueList.cpp; sourceTree = "<group>"; };
+ 9A35765E116E76A700E8ED2F /* StringList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringList.h; path = include/lldb/Core/StringList.h; sourceTree = "<group>"; };
+ 9A35765F116E76B900E8ED2F /* StringList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringList.cpp; path = source/Core/StringList.cpp; sourceTree = "<group>"; };
+ 9A357670116E7B5200E8ED2F /* SBStringList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBStringList.h; path = include/lldb/API/SBStringList.h; sourceTree = "<group>"; };
+ 9A357672116E7B6400E8ED2F /* SBStringList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBStringList.cpp; path = source/API/SBStringList.cpp; sourceTree = "<group>"; };
+ 9A3576A7116E9AB700E8ED2F /* SBHostOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBHostOS.h; path = include/lldb/API/SBHostOS.h; sourceTree = "<group>"; };
+ 9A3576A9116E9AC700E8ED2F /* SBHostOS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBHostOS.cpp; path = source/API/SBHostOS.cpp; sourceTree = "<group>"; };
+ 9A42976111861A9F00FE05CD /* CommandObjectBreakpointCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectBreakpointCommand.h; path = source/Commands/CommandObjectBreakpointCommand.h; sourceTree = "<group>"; };
+ 9A42976211861AA600FE05CD /* CommandObjectBreakpointCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectBreakpointCommand.cpp; path = source/Commands/CommandObjectBreakpointCommand.cpp; sourceTree = "<group>"; };
+ 9A633FE7112DCE3C001A7E43 /* SBFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBFrame.cpp; path = source/API/SBFrame.cpp; sourceTree = "<group>"; };
+ 9A633FE8112DCE3C001A7E43 /* SBFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBFrame.h; path = include/lldb/API/SBFrame.h; sourceTree = "<group>"; };
+ 9A82010B10FFB49800182560 /* ScriptInterpreter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScriptInterpreter.cpp; path = source/Interpreter/ScriptInterpreter.cpp; sourceTree = "<group>"; };
+ 9A8B4EA210FD515000C68FF2 /* CommandObjectUnalias.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectUnalias.h; path = source/Commands/CommandObjectUnalias.h; sourceTree = "<group>"; };
+ 9A8B4EA310FD516400C68FF2 /* CommandObjectUnalias.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectUnalias.cpp; path = source/Commands/CommandObjectUnalias.cpp; sourceTree = "<group>"; };
+ 9A9830F21125FC5800A56CB0 /* SBBroadcaster.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBBroadcaster.cpp; path = source/API/SBBroadcaster.cpp; sourceTree = "<group>"; };
+ 9A9830F31125FC5800A56CB0 /* SBBroadcaster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBBroadcaster.h; path = include/lldb/API/SBBroadcaster.h; sourceTree = "<group>"; };
+ 9A9830F41125FC5800A56CB0 /* SBCommandContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBCommandContext.cpp; path = source/API/SBCommandContext.cpp; sourceTree = "<group>"; };
+ 9A9830F51125FC5800A56CB0 /* SBCommandContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBCommandContext.h; path = include/lldb/API/SBCommandContext.h; sourceTree = "<group>"; };
+ 9A9830F61125FC5800A56CB0 /* SBCommandInterpreter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBCommandInterpreter.cpp; path = source/API/SBCommandInterpreter.cpp; sourceTree = "<group>"; };
+ 9A9830F71125FC5800A56CB0 /* SBCommandInterpreter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBCommandInterpreter.h; path = include/lldb/API/SBCommandInterpreter.h; sourceTree = "<group>"; };
+ 9A9830F81125FC5800A56CB0 /* SBCommandReturnObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBCommandReturnObject.cpp; path = source/API/SBCommandReturnObject.cpp; sourceTree = "<group>"; };
+ 9A9830F91125FC5800A56CB0 /* SBCommandReturnObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBCommandReturnObject.h; path = include/lldb/API/SBCommandReturnObject.h; sourceTree = "<group>"; };
+ 9A9830FA1125FC5800A56CB0 /* SBDebugger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBDebugger.cpp; path = source/API/SBDebugger.cpp; sourceTree = "<group>"; };
+ 9A9830FB1125FC5800A56CB0 /* SBDebugger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBDebugger.h; path = include/lldb/API/SBDebugger.h; sourceTree = "<group>"; };
+ 9A9830FC1125FC5800A56CB0 /* SBDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBDefines.h; path = include/lldb/API/SBDefines.h; sourceTree = "<group>"; };
+ 9A9830FD1125FC5800A56CB0 /* SBEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBEvent.cpp; path = source/API/SBEvent.cpp; sourceTree = "<group>"; };
+ 9A9830FE1125FC5800A56CB0 /* SBEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBEvent.h; path = include/lldb/API/SBEvent.h; sourceTree = "<group>"; };
+ 9A9831011125FC5800A56CB0 /* SBListener.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBListener.cpp; path = source/API/SBListener.cpp; sourceTree = "<group>"; };
+ 9A9831021125FC5800A56CB0 /* SBListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBListener.h; path = include/lldb/API/SBListener.h; sourceTree = "<group>"; };
+ 9A9831031125FC5800A56CB0 /* SBProcess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBProcess.cpp; path = source/API/SBProcess.cpp; sourceTree = "<group>"; };
+ 9A9831041125FC5800A56CB0 /* SBProcess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBProcess.h; path = include/lldb/API/SBProcess.h; sourceTree = "<group>"; };
+ 9A9831051125FC5800A56CB0 /* SBSourceManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBSourceManager.cpp; path = source/API/SBSourceManager.cpp; sourceTree = "<group>"; };
+ 9A9831061125FC5800A56CB0 /* SBSourceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBSourceManager.h; path = include/lldb/API/SBSourceManager.h; sourceTree = "<group>"; };
+ 9A9831071125FC5800A56CB0 /* SBTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBTarget.cpp; path = source/API/SBTarget.cpp; sourceTree = "<group>"; };
+ 9A9831081125FC5800A56CB0 /* SBTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBTarget.h; path = include/lldb/API/SBTarget.h; sourceTree = "<group>"; };
+ 9A9831091125FC5800A56CB0 /* SBThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBThread.cpp; path = source/API/SBThread.cpp; sourceTree = "<group>"; };
+ 9A98310A1125FC5800A56CB0 /* SBThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBThread.h; path = include/lldb/API/SBThread.h; sourceTree = "<group>"; };
+ 9AA69DAE118A023300D753A0 /* SBInputReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBInputReader.h; path = include/lldb/API/SBInputReader.h; sourceTree = "<group>"; };
+ 9AA69DB0118A024600D753A0 /* SBInputReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBInputReader.cpp; path = source/API/SBInputReader.cpp; sourceTree = "<group>"; };
+ 9AA69DB5118A027A00D753A0 /* InputReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InputReader.cpp; path = source/Core/InputReader.cpp; sourceTree = "<group>"; };
+ 9AA69DBB118A029E00D753A0 /* InputReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InputReader.h; path = include/lldb/Core/InputReader.h; sourceTree = "<group>"; };
+ 9AC7033D11752C4C0086C050 /* AddressResolverFileLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AddressResolverFileLine.h; path = include/lldb/Core/AddressResolverFileLine.h; sourceTree = "<group>"; };
+ 9AC7033E11752C540086C050 /* AddressResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AddressResolver.h; path = include/lldb/Core/AddressResolver.h; sourceTree = "<group>"; };
+ 9AC7033F11752C590086C050 /* AddressResolverName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AddressResolverName.h; path = include/lldb/Core/AddressResolverName.h; sourceTree = "<group>"; };
+ 9AC7034011752C6B0086C050 /* AddressResolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AddressResolver.cpp; path = source/Core/AddressResolver.cpp; sourceTree = "<group>"; };
+ 9AC7034211752C720086C050 /* AddressResolverFileLine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AddressResolverFileLine.cpp; path = source/Core/AddressResolverFileLine.cpp; sourceTree = "<group>"; };
+ 9AC7034411752C790086C050 /* AddressResolverName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AddressResolverName.cpp; path = source/Core/AddressResolverName.cpp; sourceTree = "<group>"; };
+ 9AC7038D117674EB0086C050 /* SBInstruction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBInstruction.h; path = include/lldb/API/SBInstruction.h; sourceTree = "<group>"; };
+ 9AC7038F117675270086C050 /* SBInstructionList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBInstructionList.h; path = include/lldb/API/SBInstructionList.h; sourceTree = "<group>"; };
+ 9AC703AE117675410086C050 /* SBInstruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBInstruction.cpp; path = source/API/SBInstruction.cpp; sourceTree = "<group>"; };
+ 9AC703B0117675490086C050 /* SBInstructionList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBInstructionList.cpp; path = source/API/SBInstructionList.cpp; sourceTree = "<group>"; };
+ 9AF16A9C11402D5B007A7B3F /* SBBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBBreakpoint.cpp; path = source/API/SBBreakpoint.cpp; sourceTree = "<group>"; };
+ 9AF16A9E11402D69007A7B3F /* SBBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBBreakpoint.h; path = include/lldb/API/SBBreakpoint.h; sourceTree = "<group>"; };
+ 9AF16CC611408686007A7B3F /* SBBreakpointLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBBreakpointLocation.h; path = include/lldb/API/SBBreakpointLocation.h; sourceTree = "<group>"; };
+ 9AF16CC7114086A1007A7B3F /* SBBreakpointLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBBreakpointLocation.cpp; path = source/API/SBBreakpointLocation.cpp; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 26680205115FD0ED008E1FE4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2668022F115FD19D008E1FE4 /* CoreFoundation.framework in Frameworks */,
+ 26680230115FD19E008E1FE4 /* DebugSymbols.framework in Frameworks */,
+ 26680231115FD1A0008E1FE4 /* Foundation.framework in Frameworks */,
+ 26680232115FD1A4008E1FE4 /* libpython2.6.dylib in Frameworks */,
+ 26680233115FD1A7008E1FE4 /* libobjc.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 26F5C26810F3D9A4009D5894 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 26F5C32510F3DF23009D5894 /* libpython2.6.dylib in Frameworks */,
+ 26F5C32C10F3DFDD009D5894 /* libedit.dylib in Frameworks */,
+ 26F5C32D10F3DFDD009D5894 /* libtermcap.dylib in Frameworks */,
+ 26F5C37510F3F61B009D5894 /* libobjc.dylib in Frameworks */,
+ 26F5C39110F3FA26009D5894 /* CoreFoundation.framework in Frameworks */,
+ 265ABF6310F42EE900531910 /* DebugSymbols.framework in Frameworks */,
+ 260C876A10F538E700BB2B04 /* Foundation.framework in Frameworks */,
+ 2668035C11601108008E1FE4 /* LLDB.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* lldb */ = {
+ isa = PBXGroup;
+ children = (
+ 26C9DF02113C5B80006B0F94 /* Include */,
+ 26F5C32810F3DF7D009D5894 /* Libraries */,
+ 266960581199F4230075C61A /* Scripts */,
+ 08FB7795FE84155DC02AAC07 /* Source */,
+ 26F5C22410F3D950009D5894 /* Tools */,
+ 1AB674ADFE9D54B511CA2CBB /* Products */,
+ );
+ name = lldb;
+ sourceTree = "<group>";
+ };
+ 08FB7795FE84155DC02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 26BC7E7410F1B85900F91463 /* lldb.cpp */,
+ 26BC7E7510F1B85900F91463 /* lldb-log.cpp */,
+ 26BC7C2A10F1B3BC00F91463 /* lldb-private.h */,
+ 26BC7C2810F1B3BC00F91463 /* lldb-private-interfaces.h */,
+ 26BC7D5D10F1B77400F91463 /* lldb-private-log.h */,
+ 262D3190111B4341004E6F88 /* API */,
+ 26BC7CEB10F1B70800F91463 /* Breakpoint */,
+ 26BC7D0D10F1B71D00F91463 /* Commands */,
+ 26BC7C1010F1B34800F91463 /* Core */,
+ 26BC7DBE10F1B78200F91463 /* Expression */,
+ 26BC7DD010F1B7C100F91463 /* Host */,
+ 26BC7DDF10F1B7E200F91463 /* Interpreter */,
+ 260C897110F57C5600BB2B04 /* Plugins */,
+ 26BC7C4B10F1B6C100F91463 /* Symbol */,
+ 26BC7DEF10F1B80200F91463 /* Target */,
+ 2682F168115ED9C800CCFF99 /* Utility */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ usesTabs = 0;
+ };
+ 1AB674ADFE9D54B511CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 26F5C26A10F3D9A4009D5894 /* lldb */,
+ 26680207115FD0ED008E1FE4 /* LLDB.framework */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ usesTabs = 0;
+ };
+ 260C897110F57C5600BB2B04 /* Plugins */ = {
+ isa = PBXGroup;
+ children = (
+ 493C63D711891A8000914D5E /* ABI */,
+ 260C897210F57C5600BB2B04 /* Disassembler */,
+ 260C897810F57C5600BB2B04 /* DynamicLoader */,
+ 260C897E10F57C5600BB2B04 /* ObjectContainer */,
+ 260C898210F57C5600BB2B04 /* ObjectFile */,
+ 260C898A10F57C5600BB2B04 /* Process */,
+ 260C89B110F57C5600BB2B04 /* SymbolFile */,
+ 260C89E010F57C5600BB2B04 /* SymbolVendor */,
+ );
+ name = Plugins;
+ path = source/Plugins;
+ sourceTree = "<group>";
+ };
+ 260C897210F57C5600BB2B04 /* Disassembler */ = {
+ isa = PBXGroup;
+ children = (
+ 260C897310F57C5600BB2B04 /* llvm */,
+ );
+ path = Disassembler;
+ sourceTree = "<group>";
+ };
+ 260C897310F57C5600BB2B04 /* llvm */ = {
+ isa = PBXGroup;
+ children = (
+ 260C897410F57C5600BB2B04 /* DisassemblerLLVM.cpp */,
+ 260C897510F57C5600BB2B04 /* DisassemblerLLVM.h */,
+ );
+ path = llvm;
+ sourceTree = "<group>";
+ };
+ 260C897810F57C5600BB2B04 /* DynamicLoader */ = {
+ isa = PBXGroup;
+ children = (
+ 260C897910F57C5600BB2B04 /* MacOSX-DYLD */,
+ );
+ path = DynamicLoader;
+ sourceTree = "<group>";
+ };
+ 260C897910F57C5600BB2B04 /* MacOSX-DYLD */ = {
+ isa = PBXGroup;
+ children = (
+ 260C897A10F57C5600BB2B04 /* DynamicLoaderMacOSXDYLD.cpp */,
+ 260C897B10F57C5600BB2B04 /* DynamicLoaderMacOSXDYLD.h */,
+ 260C897C10F57C5600BB2B04 /* DynamicLoaderMacOSXDYLDLog.cpp */,
+ 260C897D10F57C5600BB2B04 /* DynamicLoaderMacOSXDYLDLog.h */,
+ 4C51FF1511A4C485007C962F /* ObjCTrampolineHandler.h */,
+ 4C51FF1611A4C486007C962F /* ObjCTrampolineHandler.cpp */,
+ 4CF4473D11A8687100EF971E /* ThreadPlanStepThroughObjCTrampoline.h */,
+ 4CF4473E11A8687100EF971E /* ThreadPlanStepThroughObjCTrampoline.cpp */,
+ );
+ path = "MacOSX-DYLD";
+ sourceTree = "<group>";
+ };
+ 260C897E10F57C5600BB2B04 /* ObjectContainer */ = {
+ isa = PBXGroup;
+ children = (
+ 26A3B4AB1181454800381BC2 /* BSD-Archive */,
+ 260C897F10F57C5600BB2B04 /* Universal-Mach-O */,
+ );
+ path = ObjectContainer;
+ sourceTree = "<group>";
+ };
+ 260C897F10F57C5600BB2B04 /* Universal-Mach-O */ = {
+ isa = PBXGroup;
+ children = (
+ 260C898010F57C5600BB2B04 /* ObjectContainerUniversalMachO.cpp */,
+ 260C898110F57C5600BB2B04 /* ObjectContainerUniversalMachO.h */,
+ );
+ path = "Universal-Mach-O";
+ sourceTree = "<group>";
+ };
+ 260C898210F57C5600BB2B04 /* ObjectFile */ = {
+ isa = PBXGroup;
+ children = (
+ 260C898310F57C5600BB2B04 /* ELF */,
+ 260C898710F57C5600BB2B04 /* Mach-O */,
+ );
+ path = ObjectFile;
+ sourceTree = "<group>";
+ };
+ 260C898310F57C5600BB2B04 /* ELF */ = {
+ isa = PBXGroup;
+ children = (
+ 260C898410F57C5600BB2B04 /* elf.h */,
+ 260C898510F57C5600BB2B04 /* ObjectFileELF.cpp */,
+ 260C898610F57C5600BB2B04 /* ObjectFileELF.h */,
+ );
+ path = ELF;
+ sourceTree = "<group>";
+ };
+ 260C898710F57C5600BB2B04 /* Mach-O */ = {
+ isa = PBXGroup;
+ children = (
+ 260C898810F57C5600BB2B04 /* ObjectFileMachO.cpp */,
+ 260C898910F57C5600BB2B04 /* ObjectFileMachO.h */,
+ );
+ path = "Mach-O";
+ sourceTree = "<group>";
+ };
+ 260C898A10F57C5600BB2B04 /* Process */ = {
+ isa = PBXGroup;
+ children = (
+ 4CEE62F71145F1C70064CF93 /* GDB Remote */,
+ 260C898B10F57C5600BB2B04 /* MacOSX-User */,
+ 26B4666E11A2080F00CF6220 /* Utility */,
+ );
+ path = Process;
+ sourceTree = "<group>";
+ };
+ 260C898B10F57C5600BB2B04 /* MacOSX-User */ = {
+ isa = PBXGroup;
+ children = (
+ 260C898C10F57C5600BB2B04 /* scripts */,
+ 260C899010F57C5600BB2B04 /* source */,
+ );
+ path = "MacOSX-User";
+ sourceTree = "<group>";
+ };
+ 260C898C10F57C5600BB2B04 /* scripts */ = {
+ isa = PBXGroup;
+ children = (
+ 260C898D10F57C5600BB2B04 /* cc-swig */,
+ 260C898E10F57C5600BB2B04 /* config.pl */,
+ 260C898F10F57C5600BB2B04 /* test-ProcessDebug.pl */,
+ );
+ path = scripts;
+ sourceTree = "<group>";
+ };
+ 260C899010F57C5600BB2B04 /* source */ = {
+ isa = PBXGroup;
+ children = (
+ 260C899110F57C5600BB2B04 /* MacOSX */,
+ 260C89A310F57C5600BB2B04 /* ProcessMacOSX.cpp */,
+ 260C89A410F57C5600BB2B04 /* ProcessMacOSX.h */,
+ 260C89A510F57C5600BB2B04 /* ProcessMacOSXLog.cpp */,
+ 260C89A610F57C5600BB2B04 /* ProcessMacOSXLog.h */,
+ 260C89A910F57C5600BB2B04 /* RegisterContextMach_arm.cpp */,
+ 260C89AA10F57C5600BB2B04 /* RegisterContextMach_arm.h */,
+ 260C89AB10F57C5600BB2B04 /* RegisterContextMach_i386.cpp */,
+ 260C89AC10F57C5600BB2B04 /* RegisterContextMach_i386.h */,
+ 260C89AD10F57C5600BB2B04 /* RegisterContextMach_x86_64.cpp */,
+ 260C89AE10F57C5600BB2B04 /* RegisterContextMach_x86_64.h */,
+ 260C89AF10F57C5600BB2B04 /* ThreadMacOSX.cpp */,
+ 260C89B010F57C5600BB2B04 /* ThreadMacOSX.h */,
+ );
+ path = source;
+ sourceTree = "<group>";
+ };
+ 260C899110F57C5600BB2B04 /* MacOSX */ = {
+ isa = PBXGroup;
+ children = (
+ 260C899210F57C5600BB2B04 /* MachException.cpp */,
+ 260C899310F57C5600BB2B04 /* MachException.h */,
+ 260C899410F57C5600BB2B04 /* MachTask.cpp */,
+ 260C899510F57C5600BB2B04 /* MachTask.h */,
+ 260C899610F57C5600BB2B04 /* MachThreadContext.h */,
+ 260C899710F57C5600BB2B04 /* MachThreadContext_arm.cpp */,
+ 260C899810F57C5600BB2B04 /* MachThreadContext_arm.h */,
+ 260C899910F57C5600BB2B04 /* MachThreadContext_i386.cpp */,
+ 260C899A10F57C5600BB2B04 /* MachThreadContext_i386.h */,
+ 260C899B10F57C5600BB2B04 /* MachThreadContext_x86_64.cpp */,
+ 260C899C10F57C5600BB2B04 /* MachThreadContext_x86_64.h */,
+ 260C899D10F57C5600BB2B04 /* MachVMMemory.cpp */,
+ 260C899E10F57C5600BB2B04 /* MachVMMemory.h */,
+ 260C899F10F57C5600BB2B04 /* MachVMRegion.cpp */,
+ 260C89A010F57C5600BB2B04 /* MachVMRegion.h */,
+ 260C89A110F57C5600BB2B04 /* ProcessControl-mig.defs */,
+ );
+ path = MacOSX;
+ sourceTree = "<group>";
+ };
+ 260C89B110F57C5600BB2B04 /* SymbolFile */ = {
+ isa = PBXGroup;
+ children = (
+ 260C89B210F57C5600BB2B04 /* DWARF */,
+ 260C89DD10F57C5600BB2B04 /* Symtab */,
+ );
+ path = SymbolFile;
+ sourceTree = "<group>";
+ };
+ 260C89B210F57C5600BB2B04 /* DWARF */ = {
+ isa = PBXGroup;
+ children = (
+ 260C89B310F57C5600BB2B04 /* DWARFAbbreviationDeclaration.cpp */,
+ 260C89B410F57C5600BB2B04 /* DWARFAbbreviationDeclaration.h */,
+ 260C89B610F57C5600BB2B04 /* DWARFAttribute.h */,
+ 260C89B710F57C5600BB2B04 /* DWARFCompileUnit.cpp */,
+ 260C89B810F57C5600BB2B04 /* DWARFCompileUnit.h */,
+ 260C89B910F57C5600BB2B04 /* DWARFDebugAbbrev.cpp */,
+ 260C89BA10F57C5600BB2B04 /* DWARFDebugAbbrev.h */,
+ 260C89BB10F57C5600BB2B04 /* DWARFDebugAranges.cpp */,
+ 260C89BC10F57C5600BB2B04 /* DWARFDebugAranges.h */,
+ 260C89BD10F57C5600BB2B04 /* DWARFDebugArangeSet.cpp */,
+ 260C89BE10F57C5600BB2B04 /* DWARFDebugArangeSet.h */,
+ 260C89BF10F57C5600BB2B04 /* DWARFDebugInfo.cpp */,
+ 260C89C010F57C5600BB2B04 /* DWARFDebugInfo.h */,
+ 260C89C110F57C5600BB2B04 /* DWARFDebugInfoEntry.cpp */,
+ 260C89C210F57C5600BB2B04 /* DWARFDebugInfoEntry.h */,
+ 260C89C310F57C5600BB2B04 /* DWARFDebugLine.cpp */,
+ 260C89C410F57C5600BB2B04 /* DWARFDebugLine.h */,
+ 260C89C510F57C5600BB2B04 /* DWARFDebugMacinfo.cpp */,
+ 260C89C610F57C5600BB2B04 /* DWARFDebugMacinfo.h */,
+ 260C89C710F57C5600BB2B04 /* DWARFDebugMacinfoEntry.cpp */,
+ 260C89C810F57C5600BB2B04 /* DWARFDebugMacinfoEntry.h */,
+ 260C89C910F57C5600BB2B04 /* DWARFDebugPubnames.cpp */,
+ 260C89CA10F57C5600BB2B04 /* DWARFDebugPubnames.h */,
+ 260C89CB10F57C5600BB2B04 /* DWARFDebugPubnamesSet.cpp */,
+ 260C89CC10F57C5600BB2B04 /* DWARFDebugPubnamesSet.h */,
+ 260C89CD10F57C5600BB2B04 /* DWARFDebugRanges.cpp */,
+ 260C89CE10F57C5600BB2B04 /* DWARFDebugRanges.h */,
+ 260C89CF10F57C5600BB2B04 /* DWARFDefines.c */,
+ 260C89D010F57C5600BB2B04 /* DWARFDefines.h */,
+ 260C89D110F57C5600BB2B04 /* DWARFDIECollection.cpp */,
+ 260C89D210F57C5600BB2B04 /* DWARFDIECollection.h */,
+ 260C89D310F57C5600BB2B04 /* DWARFFormValue.cpp */,
+ 260C89D410F57C5600BB2B04 /* DWARFFormValue.h */,
+ 260C89D510F57C5600BB2B04 /* DWARFLocationDescription.cpp */,
+ 260C89D610F57C5600BB2B04 /* DWARFLocationDescription.h */,
+ 260C89D710F57C5600BB2B04 /* DWARFLocationList.cpp */,
+ 260C89D810F57C5600BB2B04 /* DWARFLocationList.h */,
+ 260C89D910F57C5600BB2B04 /* SymbolFileDWARF.cpp */,
+ 260C89DA10F57C5600BB2B04 /* SymbolFileDWARF.h */,
+ 26109B3B1155D70100CC3529 /* LogChannelDWARF.cpp */,
+ 26109B3C1155D70100CC3529 /* LogChannelDWARF.h */,
+ 260C89DB10F57C5600BB2B04 /* SymbolFileDWARFDebugMap.cpp */,
+ 260C89DC10F57C5600BB2B04 /* SymbolFileDWARFDebugMap.h */,
+ );
+ path = DWARF;
+ sourceTree = "<group>";
+ };
+ 260C89DD10F57C5600BB2B04 /* Symtab */ = {
+ isa = PBXGroup;
+ children = (
+ 260C89DE10F57C5600BB2B04 /* SymbolFileSymtab.cpp */,
+ 260C89DF10F57C5600BB2B04 /* SymbolFileSymtab.h */,
+ );
+ path = Symtab;
+ sourceTree = "<group>";
+ };
+ 260C89E010F57C5600BB2B04 /* SymbolVendor */ = {
+ isa = PBXGroup;
+ children = (
+ 260C89E110F57C5600BB2B04 /* MacOSX */,
+ );
+ path = SymbolVendor;
+ sourceTree = "<group>";
+ };
+ 260C89E110F57C5600BB2B04 /* MacOSX */ = {
+ isa = PBXGroup;
+ children = (
+ 260C89E210F57C5600BB2B04 /* SymbolVendorMacOSX.cpp */,
+ 260C89E310F57C5600BB2B04 /* SymbolVendorMacOSX.h */,
+ );
+ path = MacOSX;
+ sourceTree = "<group>";
+ };
+ 262D3190111B4341004E6F88 /* API */ = {
+ isa = PBXGroup;
+ children = (
+ 26BC7C2510F1B3BC00F91463 /* lldb-defines.h */,
+ 26BC7C2610F1B3BC00F91463 /* lldb-enumerations.h */,
+ 26DE1E6911616C2E00A093E2 /* lldb-forward-rtti.h */,
+ 26DE1E6A11616C2E00A093E2 /* lldb-forward.h */,
+ 26B42B1E1187A92B0079C8C8 /* lldb-include.h */,
+ 26BC7C2910F1B3BC00F91463 /* lldb-types.h */,
+ 26B42C4C1187ABA50079C8C8 /* LLDB.h */,
+ 9A9830FC1125FC5800A56CB0 /* SBDefines.h */,
+ 26DE204211618ACA00A093E2 /* SBAddress.h */,
+ 26DE204411618ADA00A093E2 /* SBAddress.cpp */,
+ 26DE205611618FC500A093E2 /* SBBlock.h */,
+ 26DE20601161902600A093E2 /* SBBlock.cpp */,
+ 9AF16A9E11402D69007A7B3F /* SBBreakpoint.h */,
+ 9AF16A9C11402D5B007A7B3F /* SBBreakpoint.cpp */,
+ 9AF16CC611408686007A7B3F /* SBBreakpointLocation.h */,
+ 9AF16CC7114086A1007A7B3F /* SBBreakpointLocation.cpp */,
+ 9A9830F31125FC5800A56CB0 /* SBBroadcaster.h */,
+ 9A9830F21125FC5800A56CB0 /* SBBroadcaster.cpp */,
+ 9A9830F51125FC5800A56CB0 /* SBCommandContext.h */,
+ 9A9830F41125FC5800A56CB0 /* SBCommandContext.cpp */,
+ 9A9830F71125FC5800A56CB0 /* SBCommandInterpreter.h */,
+ 9A9830F61125FC5800A56CB0 /* SBCommandInterpreter.cpp */,
+ 9A9830F91125FC5800A56CB0 /* SBCommandReturnObject.h */,
+ 9A9830F81125FC5800A56CB0 /* SBCommandReturnObject.cpp */,
+ 260223E7115F06D500A601A2 /* SBCommunication.h */,
+ 260223E8115F06E500A601A2 /* SBCommunication.cpp */,
+ 26DE205411618FB800A093E2 /* SBCompileUnit.h */,
+ 26DE205E1161901B00A093E2 /* SBCompileUnit.cpp */,
+ 9A9830FB1125FC5800A56CB0 /* SBDebugger.h */,
+ 9A9830FA1125FC5800A56CB0 /* SBDebugger.cpp */,
+ 2682F286115EF3BD00CCFF99 /* SBError.h */,
+ 2682F284115EF3A700CCFF99 /* SBError.cpp */,
+ 9A9830FE1125FC5800A56CB0 /* SBEvent.h */,
+ 9A9830FD1125FC5800A56CB0 /* SBEvent.cpp */,
+ 26022531115F27FA00A601A2 /* SBFileSpec.h */,
+ 26022532115F281400A601A2 /* SBFileSpec.cpp */,
+ 9A633FE8112DCE3C001A7E43 /* SBFrame.h */,
+ 9A633FE7112DCE3C001A7E43 /* SBFrame.cpp */,
+ 26DE205211618FAC00A093E2 /* SBFunction.h */,
+ 26DE205C1161901400A093E2 /* SBFunction.cpp */,
+ 9A3576A7116E9AB700E8ED2F /* SBHostOS.h */,
+ 9A3576A9116E9AC700E8ED2F /* SBHostOS.cpp */,
+ 9AA69DAE118A023300D753A0 /* SBInputReader.h */,
+ 9AA69DB0118A024600D753A0 /* SBInputReader.cpp */,
+ 9AC7038D117674EB0086C050 /* SBInstruction.h */,
+ 9AC703AE117675410086C050 /* SBInstruction.cpp */,
+ 9AC7038F117675270086C050 /* SBInstructionList.h */,
+ 9AC703B0117675490086C050 /* SBInstructionList.cpp */,
+ 26DE205811618FE700A093E2 /* SBLineEntry.h */,
+ 26DE20621161904200A093E2 /* SBLineEntry.cpp */,
+ 9A9831021125FC5800A56CB0 /* SBListener.h */,
+ 9A9831011125FC5800A56CB0 /* SBListener.cpp */,
+ 26DE204E11618E9800A093E2 /* SBModule.h */,
+ 26DE204C11618E7A00A093E2 /* SBModule.cpp */,
+ 9A9831041125FC5800A56CB0 /* SBProcess.h */,
+ 9A9831031125FC5800A56CB0 /* SBProcess.cpp */,
+ 9A9831061125FC5800A56CB0 /* SBSourceManager.h */,
+ 9A9831051125FC5800A56CB0 /* SBSourceManager.cpp */,
+ 9A357670116E7B5200E8ED2F /* SBStringList.h */,
+ 9A357672116E7B6400E8ED2F /* SBStringList.cpp */,
+ 26DE205A11618FF600A093E2 /* SBSymbol.h */,
+ 26DE20641161904E00A093E2 /* SBSymbol.cpp */,
+ 26DE204011618AB900A093E2 /* SBSymbolContext.h */,
+ 26DE204611618AED00A093E2 /* SBSymbolContext.cpp */,
+ 9A9831081125FC5800A56CB0 /* SBTarget.h */,
+ 9A9831071125FC5800A56CB0 /* SBTarget.cpp */,
+ 9A98310A1125FC5800A56CB0 /* SBThread.h */,
+ 9A9831091125FC5800A56CB0 /* SBThread.cpp */,
+ 2617447911685869005ADD65 /* SBType.h */,
+ 261744771168585B005ADD65 /* SBType.cpp */,
+ 9A19A6A51163BB7E00E0D453 /* SBValue.h */,
+ 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */,
+ 9A357582116CFDEE00E8ED2F /* SBValueList.h */,
+ 9A35758D116CFE0F00E8ED2F /* SBValueList.cpp */,
+ );
+ name = API;
+ sourceTree = "<group>";
+ };
+ 265E9BE0115C2B8500D0DCCB /* debugserver */ = {
+ isa = PBXGroup;
+ children = (
+ 265E9BE1115C2BAA00D0DCCB /* debugserver.xcodeproj */,
+ );
+ name = debugserver;
+ sourceTree = "<group>";
+ };
+ 265E9BE2115C2BAA00D0DCCB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 26CE05A0115C31E50022F371 /* debugserver */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 266960581199F4230075C61A /* Scripts */ = {
+ isa = PBXGroup;
+ children = (
+ 266960591199F4230075C61A /* build-llvm.pl */,
+ 2669605A1199F4230075C61A /* build-swig-wrapper-classes.sh */,
+ 2669605B1199F4230075C61A /* checkpoint-llvm.pl */,
+ 2669605C1199F4230075C61A /* finish-swig-wrapper-classes.sh */,
+ 2669605D1199F4230075C61A /* install-lldb.sh */,
+ 2669605E1199F4230075C61A /* lldb.swig */,
+ 2669605F1199F4230075C61A /* Python */,
+ 266960631199F4230075C61A /* sed-sources */,
+ );
+ name = Scripts;
+ path = scripts;
+ sourceTree = "<group>";
+ };
+ 2669605F1199F4230075C61A /* Python */ = {
+ isa = PBXGroup;
+ children = (
+ 266960601199F4230075C61A /* build-swig-Python.sh */,
+ 266960611199F4230075C61A /* edit-swig-python-wrapper-file.py */,
+ 266960621199F4230075C61A /* finish-swig-Python-lldb.sh */,
+ );
+ path = Python;
+ sourceTree = "<group>";
+ };
+ 2682F168115ED9C800CCFF99 /* Utility */ = {
+ isa = PBXGroup;
+ children = (
+ 26F996A7119B79C300412154 /* ARM_DWARF_Registers.h */,
+ 26F996A8119B79C300412154 /* ARM_GCC_Registers.h */,
+ 2660D9F611922A1300958FBD /* StringExtractor.cpp */,
+ 2660D9F711922A1300958FBD /* StringExtractor.h */,
+ 2676A093119C93C8008A98EF /* StringExtractorGDBRemote.cpp */,
+ 2676A094119C93C8008A98EF /* StringExtractorGDBRemote.h */,
+ 2682F16A115EDA0D00CCFF99 /* PseudoTerminal.cpp */,
+ 2682F16B115EDA0D00CCFF99 /* PseudoTerminal.h */,
+ );
+ name = Utility;
+ sourceTree = "<group>";
+ };
+ 26A3B4AB1181454800381BC2 /* BSD-Archive */ = {
+ isa = PBXGroup;
+ children = (
+ 26A3B4AC1181454800381BC2 /* ObjectContainerBSDArchive.cpp */,
+ 26A3B4AD1181454800381BC2 /* ObjectContainerBSDArchive.h */,
+ );
+ path = "BSD-Archive";
+ sourceTree = "<group>";
+ };
+ 26B4666E11A2080F00CF6220 /* Utility */ = {
+ isa = PBXGroup;
+ children = (
+ 9654F79F1197DA3F00F72B43 /* libunwind */,
+ 26B4666F11A2091600CF6220 /* LibUnwindRegisterContext.cpp */,
+ 26B4667011A2091600CF6220 /* LibUnwindRegisterContext.h */,
+ 9654F79C1197DA1300F72B43 /* MacOSXLibunwindCallbacks.cpp */,
+ 9654F79D1197DA1300F72B43 /* MacOSXLibunwindCallbacks.h */,
+ 26E3EEF711A994E800FBADB6 /* RegisterContextMacOSXFrameBackchain.cpp */,
+ 26E3EEF811A994E800FBADB6 /* RegisterContextMacOSXFrameBackchain.h */,
+ 26E3EEBE11A98A1900FBADB6 /* UnwindLibUnwind.cpp */,
+ 26E3EEBF11A98A1900FBADB6 /* UnwindLibUnwind.h */,
+ 26E3EEE311A9901300FBADB6 /* UnwindMacOSXFrameBackchain.cpp */,
+ 26E3EEE411A9901300FBADB6 /* UnwindMacOSXFrameBackchain.h */,
+ );
+ name = Utility;
+ sourceTree = "<group>";
+ };
+ 26BC7C1010F1B34800F91463 /* Core */ = {
+ isa = PBXGroup;
+ children = (
+ 26BC7D5010F1B77400F91463 /* Address.h */,
+ 26BC7E6910F1B85900F91463 /* Address.cpp */,
+ 26BC7D5110F1B77400F91463 /* AddressRange.h */,
+ 26BC7E6A10F1B85900F91463 /* AddressRange.cpp */,
+ 9AC7033E11752C540086C050 /* AddressResolver.h */,
+ 9AC7034011752C6B0086C050 /* AddressResolver.cpp */,
+ 9AC7033D11752C4C0086C050 /* AddressResolverFileLine.h */,
+ 9AC7034211752C720086C050 /* AddressResolverFileLine.cpp */,
+ 9AC7033F11752C590086C050 /* AddressResolverName.h */,
+ 9AC7034411752C790086C050 /* AddressResolverName.cpp */,
+ 26BC7D5210F1B77400F91463 /* ArchSpec.h */,
+ 26BC7E6B10F1B85900F91463 /* ArchSpec.cpp */,
+ 26BC7D5310F1B77400F91463 /* Args.h */,
+ 26BC7E6C10F1B85900F91463 /* Args.cpp */,
+ 26A0604711A5BC7A00F75969 /* Baton.h */,
+ 26A0604811A5D03C00F75969 /* Baton.cpp */,
+ 26BC7D5410F1B77400F91463 /* Broadcaster.h */,
+ 26BC7E6D10F1B85900F91463 /* Broadcaster.cpp */,
+ 26BC7D5510F1B77400F91463 /* ClangForward.h */,
+ 26BC7D5610F1B77400F91463 /* Communication.h */,
+ 26BC7E6E10F1B85900F91463 /* Communication.cpp */,
+ 26BC7D5710F1B77400F91463 /* Connection.h */,
+ 26BC7E6F10F1B85900F91463 /* Connection.cpp */,
+ 26BC7D5810F1B77400F91463 /* ConnectionFileDescriptor.h */,
+ 26BC7E7010F1B85900F91463 /* ConnectionFileDescriptor.cpp */,
+ 26BC7D7C10F1B77400F91463 /* ConstString.h */,
+ 26BC7E9410F1B85900F91463 /* ConstString.cpp */,
+ 26BC7D5910F1B77400F91463 /* DataBuffer.h */,
+ 26BC7D5B10F1B77400F91463 /* DataBufferHeap.h */,
+ 26BC7E7210F1B85900F91463 /* DataBufferHeap.cpp */,
+ 26BC7D5C10F1B77400F91463 /* DataBufferMemoryMap.h */,
+ 26BC7E7310F1B85900F91463 /* DataBufferMemoryMap.cpp */,
+ 26BC7D5A10F1B77400F91463 /* DataExtractor.h */,
+ 26BC7E7110F1B85900F91463 /* DataExtractor.cpp */,
+ 263664941140A4C10075843B /* Debugger.h */,
+ 263664921140A4930075843B /* Debugger.cpp */,
+ 26BC7D5E10F1B77400F91463 /* Disassembler.h */,
+ 26BC7E7610F1B85900F91463 /* Disassembler.cpp */,
+ 26BC7D5F10F1B77400F91463 /* dwarf.h */,
+ 26BC7E7710F1B85900F91463 /* DynamicLoader.cpp */,
+ 26BC7D6010F1B77400F91463 /* Error.h */,
+ 26BC7E7810F1B85900F91463 /* Error.cpp */,
+ 26BC7D6110F1B77400F91463 /* Event.h */,
+ 26BC7E7910F1B85900F91463 /* Event.cpp */,
+ 26BC7D6210F1B77400F91463 /* FileSpec.h */,
+ 26BC7E7A10F1B85900F91463 /* FileSpec.cpp */,
+ 26BC7D6310F1B77400F91463 /* FileSpecList.h */,
+ 26BC7E7B10F1B85900F91463 /* FileSpecList.cpp */,
+ 26BC7D6410F1B77400F91463 /* Flags.h */,
+ 26BC7E7C10F1B85900F91463 /* Flags.cpp */,
+ 9AA69DBB118A029E00D753A0 /* InputReader.h */,
+ 9AA69DB5118A027A00D753A0 /* InputReader.cpp */,
+ 26BC7D6510F1B77400F91463 /* IOStreamMacros.h */,
+ 26BC7D6610F1B77400F91463 /* Language.h */,
+ 26BC7E7D10F1B85900F91463 /* Language.cpp */,
+ 26BC7D6710F1B77400F91463 /* Listener.h */,
+ 26BC7E7E10F1B85900F91463 /* Listener.cpp */,
+ 26BC7D6810F1B77400F91463 /* Log.h */,
+ 26BC7E7F10F1B85900F91463 /* Log.cpp */,
+ 26BC7D6910F1B77400F91463 /* Mangled.h */,
+ 26BC7E8010F1B85900F91463 /* Mangled.cpp */,
+ 26BC7D6A10F1B77400F91463 /* Module.h */,
+ 26BC7E8110F1B85900F91463 /* Module.cpp */,
+ 26BC7D6B10F1B77400F91463 /* ModuleChild.h */,
+ 26BC7E8210F1B85900F91463 /* ModuleChild.cpp */,
+ 26BC7D6C10F1B77400F91463 /* ModuleList.h */,
+ 26BC7E8310F1B85900F91463 /* ModuleList.cpp */,
+ 26BC7D6D10F1B77400F91463 /* Options.h */,
+ 26BC7E8610F1B85900F91463 /* Options.cpp */,
+ 26BC7D7010F1B77400F91463 /* PluginInterface.h */,
+ 26BC7D7110F1B77400F91463 /* PluginManager.h */,
+ 26BC7E8A10F1B85900F91463 /* PluginManager.cpp */,
+ 26BC7D7310F1B77400F91463 /* RegularExpression.h */,
+ 26BC7E8C10F1B85900F91463 /* RegularExpression.cpp */,
+ 26BC7D7410F1B77400F91463 /* Scalar.h */,
+ 26BC7E8D10F1B85900F91463 /* Scalar.cpp */,
+ 26BC7CF910F1B71400F91463 /* SearchFilter.h */,
+ 26BC7E1510F1B83100F91463 /* SearchFilter.cpp */,
+ 26BC7D7510F1B77400F91463 /* Section.h */,
+ 26BC7E8E10F1B85900F91463 /* Section.cpp */,
+ 26BC7D7610F1B77400F91463 /* SourceManager.h */,
+ 26BC7E8F10F1B85900F91463 /* SourceManager.cpp */,
+ 26BC7D7710F1B77400F91463 /* State.h */,
+ 26BC7E9010F1B85900F91463 /* State.cpp */,
+ 26BC7D7810F1B77400F91463 /* STLUtils.h */,
+ 26BC7D7910F1B77400F91463 /* Stream.h */,
+ 26BC7E9110F1B85900F91463 /* Stream.cpp */,
+ 26BC7D7A10F1B77400F91463 /* StreamFile.h */,
+ 26BC7E9210F1B85900F91463 /* StreamFile.cpp */,
+ 26BC7D7B10F1B77400F91463 /* StreamString.h */,
+ 26BC7E9310F1B85900F91463 /* StreamString.cpp */,
+ 9A35765E116E76A700E8ED2F /* StringList.h */,
+ 9A35765F116E76B900E8ED2F /* StringList.cpp */,
+ 26BC7D7E10F1B77400F91463 /* Timer.h */,
+ 26BC7E9610F1B85900F91463 /* Timer.cpp */,
+ 26BC7D7F10F1B77400F91463 /* TTYState.h */,
+ 26BC7E9710F1B85900F91463 /* TTYState.cpp */,
+ 268A813F115B19D000F645B0 /* UniqueCStringMap.h */,
+ 26BC7D8010F1B77400F91463 /* UserID.h */,
+ 26BC7E9810F1B85900F91463 /* UserID.cpp */,
+ 26BC7D8110F1B77400F91463 /* Value.h */,
+ 26BC7E9910F1B85900F91463 /* Value.cpp */,
+ 26BC7D8210F1B77400F91463 /* ValueObject.h */,
+ 26BC7E9A10F1B85900F91463 /* ValueObject.cpp */,
+ 26BC7D8310F1B77400F91463 /* ValueObjectChild.h */,
+ 26BC7E9B10F1B85900F91463 /* ValueObjectChild.cpp */,
+ 26BC7D8410F1B77400F91463 /* ValueObjectList.h */,
+ 26BC7E9C10F1B85900F91463 /* ValueObjectList.cpp */,
+ 2643343A1110F63C00CDB6C6 /* ValueObjectRegister.h */,
+ 264334381110F63100CDB6C6 /* ValueObjectRegister.cpp */,
+ 26BC7D8510F1B77400F91463 /* ValueObjectVariable.h */,
+ 26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */,
+ 26BC7D8610F1B77400F91463 /* VMRange.h */,
+ 26BC7E9E10F1B85900F91463 /* VMRange.cpp */,
+ 26B167A41123BF5500DC7B4F /* ThreadSafeValue.h */,
+ 263FEDA5112CC1DA00E4C208 /* ThreadSafeSTLMap.h */,
+ 26C81CA411335651004BDC5A /* UUID.h */,
+ 26C81CA511335651004BDC5A /* UUID.cpp */,
+ );
+ name = Core;
+ sourceTree = "<group>";
+ };
+ 26BC7C4B10F1B6C100F91463 /* Symbol */ = {
+ isa = PBXGroup;
+ children = (
+ 26BC7C5510F1B6E900F91463 /* Block.h */,
+ 26BC7F1310F1B8EC00F91463 /* Block.cpp */,
+ 26BC7C5610F1B6E900F91463 /* ClangASTContext.h */,
+ 26BC7F1410F1B8EC00F91463 /* ClangASTContext.cpp */,
+ 26BC7C5710F1B6E900F91463 /* CompileUnit.h */,
+ 26BC7F1510F1B8EC00F91463 /* CompileUnit.cpp */,
+ 26BC7C5810F1B6E900F91463 /* Declaration.h */,
+ 26BC7F1610F1B8EC00F91463 /* Declaration.cpp */,
+ 26BC7C5910F1B6E900F91463 /* DWARFCallFrameInfo.h */,
+ 26BC7F1710F1B8EC00F91463 /* DWARFCallFrameInfo.cpp */,
+ 26BC7C5A10F1B6E900F91463 /* Function.h */,
+ 26BC7F1810F1B8EC00F91463 /* Function.cpp */,
+ 26BC7C5B10F1B6E900F91463 /* LineEntry.h */,
+ 26BC7F1910F1B8EC00F91463 /* LineEntry.cpp */,
+ 26BC7C5C10F1B6E900F91463 /* LineTable.h */,
+ 26BC7F1A10F1B8EC00F91463 /* LineTable.cpp */,
+ 26BC7C5D10F1B6E900F91463 /* ObjectContainer.h */,
+ 26BC7C5E10F1B6E900F91463 /* ObjectFile.h */,
+ 26BC7F4C10F1BC1A00F91463 /* ObjectFile.cpp */,
+ 26BC7C5F10F1B6E900F91463 /* Symbol.h */,
+ 26BC7F1B10F1B8EC00F91463 /* Symbol.cpp */,
+ 26BC7C6010F1B6E900F91463 /* SymbolContext.h */,
+ 26BC7F1C10F1B8EC00F91463 /* SymbolContext.cpp */,
+ 26BC7C6110F1B6E900F91463 /* SymbolContextScope.h */,
+ 26BC7C6210F1B6E900F91463 /* SymbolFile.h */,
+ 26BC7F1D10F1B8EC00F91463 /* SymbolFile.cpp */,
+ 26BC7C6310F1B6E900F91463 /* SymbolVendor.h */,
+ 26BC7F1E10F1B8EC00F91463 /* SymbolVendor.mm */,
+ 26BC7C6410F1B6E900F91463 /* Symtab.h */,
+ 26BC7F1F10F1B8EC00F91463 /* Symtab.cpp */,
+ 26BC7C6510F1B6E900F91463 /* Type.h */,
+ 26BC7F2010F1B8EC00F91463 /* Type.cpp */,
+ 26BC7C6610F1B6E900F91463 /* TypeList.h */,
+ 26BC7F2110F1B8EC00F91463 /* TypeList.cpp */,
+ 26BC7C6710F1B6E900F91463 /* Variable.h */,
+ 26BC7F2210F1B8EC00F91463 /* Variable.cpp */,
+ 26BC7C6810F1B6E900F91463 /* VariableList.h */,
+ 26BC7F2310F1B8EC00F91463 /* VariableList.cpp */,
+ );
+ name = Symbol;
+ sourceTree = "<group>";
+ };
+ 26BC7CEB10F1B70800F91463 /* Breakpoint */ = {
+ isa = PBXGroup;
+ children = (
+ 26BC7CEE10F1B71400F91463 /* Breakpoint.h */,
+ 26BC7E0A10F1B83100F91463 /* Breakpoint.cpp */,
+ 26BC7CEF10F1B71400F91463 /* BreakpointID.h */,
+ 26BC7E0B10F1B83100F91463 /* BreakpointID.cpp */,
+ 26BC7CF010F1B71400F91463 /* BreakpointIDList.h */,
+ 26BC7E0C10F1B83100F91463 /* BreakpointIDList.cpp */,
+ 26BC7CF110F1B71400F91463 /* BreakpointList.h */,
+ 26BC7E0D10F1B83100F91463 /* BreakpointList.cpp */,
+ 26BC7CF210F1B71400F91463 /* BreakpointLocation.h */,
+ 26BC7E0E10F1B83100F91463 /* BreakpointLocation.cpp */,
+ 26BC7CF310F1B71400F91463 /* BreakpointLocationCollection.h */,
+ 26BC7E0F10F1B83100F91463 /* BreakpointLocationCollection.cpp */,
+ 26BC7CF410F1B71400F91463 /* BreakpointLocationList.h */,
+ 26BC7E1010F1B83100F91463 /* BreakpointLocationList.cpp */,
+ 26BC7CF510F1B71400F91463 /* BreakpointOptions.h */,
+ 26BC7E1110F1B83100F91463 /* BreakpointOptions.cpp */,
+ 26BC7CF610F1B71400F91463 /* BreakpointResolver.h */,
+ 26BC7E1210F1B83100F91463 /* BreakpointResolver.cpp */,
+ 26D0DD5010FE554D00271C65 /* BreakpointResolverAddress.h */,
+ 26D0DD5310FE555900271C65 /* BreakpointResolverAddress.cpp */,
+ 26D0DD5110FE554D00271C65 /* BreakpointResolverFileLine.h */,
+ 26D0DD5410FE555900271C65 /* BreakpointResolverFileLine.cpp */,
+ 26D0DD5210FE554D00271C65 /* BreakpointResolverName.h */,
+ 26D0DD5510FE555900271C65 /* BreakpointResolverName.cpp */,
+ 26BC7CF710F1B71400F91463 /* BreakpointSite.h */,
+ 26BC7E1310F1B83100F91463 /* BreakpointSite.cpp */,
+ 26BC7CF810F1B71400F91463 /* BreakpointSiteList.h */,
+ 26BC7E1410F1B83100F91463 /* BreakpointSiteList.cpp */,
+ 26BC7CFA10F1B71400F91463 /* Stoppoint.h */,
+ 26BC7E1610F1B83100F91463 /* Stoppoint.cpp */,
+ 26BC7CED10F1B71400F91463 /* StoppointCallbackContext.h */,
+ 26BC7E0910F1B83100F91463 /* StoppointCallbackContext.cpp */,
+ 26BC7CFB10F1B71400F91463 /* StoppointLocation.h */,
+ 26BC7E1710F1B83100F91463 /* StoppointLocation.cpp */,
+ 26BC7CFC10F1B71400F91463 /* WatchpointLocation.h */,
+ 26BC7E1810F1B83100F91463 /* WatchpointLocation.cpp */,
+ );
+ name = Breakpoint;
+ sourceTree = "<group>";
+ };
+ 26BC7D0D10F1B71D00F91463 /* Commands */ = {
+ isa = PBXGroup;
+ children = (
+ 26BC7D1010F1B76300F91463 /* CommandObjectAdd.h */,
+ 26BC7E2910F1B84700F91463 /* CommandObjectAdd.cpp */,
+ 26BC7D1110F1B76300F91463 /* CommandObjectAlias.h */,
+ 26BC7E2A10F1B84700F91463 /* CommandObjectAlias.cpp */,
+ 26BC7D1210F1B76300F91463 /* CommandObjectAppend.h */,
+ 26BC7E2B10F1B84700F91463 /* CommandObjectAppend.cpp */,
+ 4CA9637A11B6E99A00780E28 /* CommandObjectApropos.h */,
+ 4CA9637911B6E99A00780E28 /* CommandObjectApropos.cpp */,
+ 499F381E11A5B3F300F5CE02 /* CommandObjectArgs.h */,
+ 499F381F11A5B3F300F5CE02 /* CommandObjectArgs.cpp */,
+ 26BC7D1410F1B76300F91463 /* CommandObjectBreakpoint.h */,
+ 26BC7E2D10F1B84700F91463 /* CommandObjectBreakpoint.cpp */,
+ 9A42976111861A9F00FE05CD /* CommandObjectBreakpointCommand.h */,
+ 9A42976211861AA600FE05CD /* CommandObjectBreakpointCommand.cpp */,
+ 4C98D3E5118FB9B100E575D0 /* CommandObjectCall.h */,
+ 4C98D3E4118FB9B100E575D0 /* CommandObjectCall.cpp */,
+ 26BC7D1610F1B76300F91463 /* CommandObjectDelete.h */,
+ 26BC7E2F10F1B84700F91463 /* CommandObjectDelete.cpp */,
+ 26BC7D1710F1B76300F91463 /* CommandObjectDisassemble.h */,
+ 26BC7E3010F1B84700F91463 /* CommandObjectDisassemble.cpp */,
+ 26BC7D1810F1B76300F91463 /* CommandObjectExpression.h */,
+ 26BC7E3110F1B84700F91463 /* CommandObjectExpression.cpp */,
+ 26BC7D1910F1B76300F91463 /* CommandObjectFile.h */,
+ 26BC7E3210F1B84700F91463 /* CommandObjectFile.cpp */,
+ 2672D8471189055500FF4019 /* CommandObjectFrame.h */,
+ 2672D8461189055500FF4019 /* CommandObjectFrame.cpp */,
+ 26BC7D1A10F1B76300F91463 /* CommandObjectHelp.h */,
+ 26BC7E3310F1B84700F91463 /* CommandObjectHelp.cpp */,
+ 26BC7D1B10F1B76300F91463 /* CommandObjectImage.h */,
+ 26BC7E3410F1B84700F91463 /* CommandObjectImage.cpp */,
+ 26BC7D1C10F1B76300F91463 /* CommandObjectInfo.h */,
+ 26BC7E3510F1B84700F91463 /* CommandObjectInfo.cpp */,
+ 264AD83911095BBD00E0B039 /* CommandObjectLog.h */,
+ 264AD83711095BA600E0B039 /* CommandObjectLog.cpp */,
+ 26BC7D1D10F1B76300F91463 /* CommandObjectMemory.h */,
+ 26BC7E3610F1B84700F91463 /* CommandObjectMemory.cpp */,
+ 26BC7D1F10F1B76300F91463 /* CommandObjectProcess.h */,
+ 26BC7E3810F1B84700F91463 /* CommandObjectProcess.cpp */,
+ 26BC7D2010F1B76300F91463 /* CommandObjectQuit.h */,
+ 26BC7E3910F1B84700F91463 /* CommandObjectQuit.cpp */,
+ 26BC7D2210F1B76300F91463 /* CommandObjectRegister.h */,
+ 26BC7E3B10F1B84700F91463 /* CommandObjectRegister.cpp */,
+ 26BC7D2310F1B76300F91463 /* CommandObjectRemove.h */,
+ 26BC7E3C10F1B84700F91463 /* CommandObjectRemove.cpp */,
+ 26BC7D2410F1B76300F91463 /* CommandObjectScript.h */,
+ 26BC7E3D10F1B84700F91463 /* CommandObjectScript.cpp */,
+ 26BC7D2510F1B76300F91463 /* CommandObjectSelect.h */,
+ 26BC7E3E10F1B84700F91463 /* CommandObjectSelect.cpp */,
+ 26BC7D2610F1B76300F91463 /* CommandObjectSet.h */,
+ 26BC7E3F10F1B84700F91463 /* CommandObjectSet.cpp */,
+ 26BC7D2710F1B76300F91463 /* CommandObjectSettings.h */,
+ 26BC7E4010F1B84700F91463 /* CommandObjectSettings.cpp */,
+ 26BC7D2810F1B76300F91463 /* CommandObjectShow.h */,
+ 26BC7E4110F1B84700F91463 /* CommandObjectShow.cpp */,
+ 26BC7D2910F1B76300F91463 /* CommandObjectSource.h */,
+ 26BC7E4210F1B84700F91463 /* CommandObjectSource.cpp */,
+ 26BC7D2A10F1B76300F91463 /* CommandObjectSourceFile.h */,
+ 26BC7E4310F1B84700F91463 /* CommandObjectSourceFile.cpp */,
+ 26BC7D2B10F1B76300F91463 /* CommandObjectStatus.h */,
+ 26BC7E4410F1B84700F91463 /* CommandObjectStatus.cpp */,
+ 26BC7D2C10F1B76300F91463 /* CommandObjectSyntax.h */,
+ 26BC7E4510F1B84700F91463 /* CommandObjectSyntax.cpp */,
+ 269416AE119A024800FF2715 /* CommandObjectTarget.h */,
+ 269416AD119A024800FF2715 /* CommandObjectTarget.cpp */,
+ 26BC7D2D10F1B76300F91463 /* CommandObjectThread.h */,
+ 26BC7E4610F1B84700F91463 /* CommandObjectThread.cpp */,
+ 26BC7D2E10F1B76300F91463 /* CommandObjectTranslate.h */,
+ 26BC7E4710F1B84700F91463 /* CommandObjectTranslate.cpp */,
+ 9A8B4EA210FD515000C68FF2 /* CommandObjectUnalias.h */,
+ 9A8B4EA310FD516400C68FF2 /* CommandObjectUnalias.cpp */,
+ 26BC7D2F10F1B76300F91463 /* CommandObjectVariable.h */,
+ 26BC7E4810F1B84700F91463 /* CommandObjectVariable.cpp */,
+ );
+ name = Commands;
+ sourceTree = "<group>";
+ };
+ 26BC7DBE10F1B78200F91463 /* Expression */ = {
+ isa = PBXGroup;
+ children = (
+ 49D7072611B5AD03001AD875 /* ClangASTSource.h */,
+ 49D7072811B5AD11001AD875 /* ClangASTSource.cpp */,
+ 26BC7DC010F1B79500F91463 /* ClangExpression.h */,
+ 26BC7ED510F1B86700F91463 /* ClangExpression.cpp */,
+ 4C98D3E0118FB98F00E575D0 /* ClangFunction.h */,
+ 4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */,
+ 49F1A74911B338AE003ED505 /* ClangExpressionDeclMap.h */,
+ 49F1A74511B3388F003ED505 /* ClangExpressionDeclMap.cpp */,
+ 26BC7DC110F1B79500F91463 /* ClangExpressionVariable.h */,
+ 26BC7ED610F1B86700F91463 /* ClangExpressionVariable.cpp */,
+ 26BC7DC210F1B79500F91463 /* ClangStmtVisitor.h */,
+ 26BC7ED710F1B86700F91463 /* ClangStmtVisitor.cpp */,
+ 26BC7DC310F1B79500F91463 /* DWARFExpression.h */,
+ 26BC7ED810F1B86700F91463 /* DWARFExpression.cpp */,
+ 4C98D3E1118FB98F00E575D0 /* RecordingMemoryManager.h */,
+ 4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */,
+ );
+ name = Expression;
+ sourceTree = "<group>";
+ };
+ 26BC7DD010F1B7C100F91463 /* Host */ = {
+ isa = PBXGroup;
+ children = (
+ 26BC7EE510F1B88100F91463 /* MacOSX */,
+ 26BC7DD210F1B7D500F91463 /* Condition.h */,
+ 26BC7DD310F1B7D500F91463 /* Endian.h */,
+ 26BC7DD410F1B7D500F91463 /* Host.h */,
+ 26BC7DD510F1B7D500F91463 /* Mutex.h */,
+ 26BC7DD610F1B7D500F91463 /* Predicate.h */,
+ 2689B0A4113EE3CD00A4AEDB /* Symbols.h */,
+ 26B4E26E112F35F700AB3F64 /* TimeValue.h */,
+ 26BC7DD710F1B7D500F91463 /* Types.h */,
+ );
+ name = Host;
+ sourceTree = "<group>";
+ };
+ 26BC7DDF10F1B7E200F91463 /* Interpreter */ = {
+ isa = PBXGroup;
+ children = (
+ 26A4EEB511682AAC007A372A /* LLDBWrapPython.cpp */,
+ 4C09CB73116BD98B00C7A725 /* CommandCompletions.h */,
+ 4C09CB74116BD98B00C7A725 /* CommandCompletions.cpp */,
+ 26BC7DE110F1B7F900F91463 /* CommandContext.h */,
+ 26BC7F0710F1B8DD00F91463 /* CommandContext.cpp */,
+ 26BC7DE210F1B7F900F91463 /* CommandInterpreter.h */,
+ 26BC7F0810F1B8DD00F91463 /* CommandInterpreter.cpp */,
+ 26BC7DE310F1B7F900F91463 /* CommandObject.h */,
+ 26BC7F0910F1B8DD00F91463 /* CommandObject.cpp */,
+ 26DFBC50113B48D600DD817F /* CommandObjectCrossref.h */,
+ 26DFBC57113B48F300DD817F /* CommandObjectCrossref.cpp */,
+ 26DFBC51113B48D600DD817F /* CommandObjectMultiword.h */,
+ 26DFBC58113B48F300DD817F /* CommandObjectMultiword.cpp */,
+ 26DFBC52113B48D600DD817F /* CommandObjectRegexCommand.h */,
+ 26DFBC59113B48F300DD817F /* CommandObjectRegexCommand.cpp */,
+ 26BC7DE410F1B7F900F91463 /* CommandReturnObject.h */,
+ 26BC7F0A10F1B8DD00F91463 /* CommandReturnObject.cpp */,
+ 26BC7DE510F1B7F900F91463 /* ScriptInterpreter.h */,
+ 9A82010B10FFB49800182560 /* ScriptInterpreter.cpp */,
+ 9A2771FB1135A35C00E6ADB6 /* ScriptInterpreterNone.h */,
+ 9A2771FC1135A37500E6ADB6 /* ScriptInterpreterNone.cpp */,
+ 26BC7DE610F1B7F900F91463 /* ScriptInterpreterPython.h */,
+ 26BC7F0C10F1B8DD00F91463 /* ScriptInterpreterPython.cpp */,
+ 26BC7DE710F1B7F900F91463 /* StateVariable.h */,
+ 26BC7F0B10F1B8DD00F91463 /* StateVariable.cpp */,
+ );
+ name = Interpreter;
+ sourceTree = "<group>";
+ };
+ 26BC7DEF10F1B80200F91463 /* Target */ = {
+ isa = PBXGroup;
+ children = (
+ 497E7B331188ED300065CCA1 /* ABI.h */,
+ 497E7B9D1188F6690065CCA1 /* ABI.cpp */,
+ 26BC7DF110F1B81A00F91463 /* DynamicLoader.h */,
+ 26BC7DF210F1B81A00F91463 /* ExecutionContext.h */,
+ 26BC7F3510F1B90C00F91463 /* ExecutionContext.cpp */,
+ 26DAFD9711529BC7005A394E /* ExecutionContextScope.h */,
+ 49BF48E011ADF37D008863BD /* ObjCObjectPrinter.h */,
+ 49BF48DC11ADF356008863BD /* ObjCObjectPrinter.cpp */,
+ 495BBACF119A0DE700418BEA /* PathMappingList.h */,
+ 495BBACB119A0DBE00418BEA /* PathMappingList.cpp */,
+ 26BC7DF310F1B81A00F91463 /* Process.h */,
+ 26BC7F3610F1B90C00F91463 /* Process.cpp */,
+ 26BC7DF410F1B81A00F91463 /* RegisterContext.h */,
+ 26BC7F3710F1B90C00F91463 /* RegisterContext.cpp */,
+ 26BC7DF510F1B81A00F91463 /* StackFrame.h */,
+ 26BC7F3810F1B90C00F91463 /* StackFrame.cpp */,
+ 26BC7DF610F1B81A00F91463 /* StackFrameList.h */,
+ 26BC7F3910F1B90C00F91463 /* StackFrameList.cpp */,
+ 26BC7DF710F1B81A00F91463 /* StackID.h */,
+ 26BC7F3A10F1B90C00F91463 /* StackID.cpp */,
+ 26BC7DF810F1B81A00F91463 /* Target.h */,
+ 26BC7F3B10F1B90C00F91463 /* Target.cpp */,
+ 26BC7DF910F1B81A00F91463 /* TargetList.h */,
+ 26BC7F3C10F1B90C00F91463 /* TargetList.cpp */,
+ 26BC7DFA10F1B81A00F91463 /* Thread.h */,
+ 26BC7F3D10F1B90C00F91463 /* Thread.cpp */,
+ 26BC7DFB10F1B81A00F91463 /* ThreadList.h */,
+ 26BC7F3E10F1B90C00F91463 /* ThreadList.cpp */,
+ 26BC7DFC10F1B81A00F91463 /* ThreadPlan.h */,
+ 26BC7F3F10F1B90C00F91463 /* ThreadPlan.cpp */,
+ 260C847F10F50F0A00BB2B04 /* ThreadPlanBase.h */,
+ 260C847110F50EFC00BB2B04 /* ThreadPlanBase.cpp */,
+ 49EC3E9C118F90D400B1265E /* ThreadPlanCallFunction.h */,
+ 49EC3E98118F90AC00B1265E /* ThreadPlanCallFunction.cpp */,
+ 260C847E10F50F0A00BB2B04 /* ThreadPlanContinue.h */,
+ 260C847010F50EFC00BB2B04 /* ThreadPlanContinue.cpp */,
+ 4C43DEF9110641F300E55CBF /* ThreadPlanShouldStopHere.h */,
+ 4C43DEFA110641F300E55CBF /* ThreadPlanShouldStopHere.cpp */,
+ 260C848010F50F0A00BB2B04 /* ThreadPlanStepInstruction.h */,
+ 260C847210F50EFC00BB2B04 /* ThreadPlanStepInstruction.cpp */,
+ 260C848110F50F0A00BB2B04 /* ThreadPlanStepOut.h */,
+ 260C847310F50EFC00BB2B04 /* ThreadPlanStepOut.cpp */,
+ 260C848210F50F0A00BB2B04 /* ThreadPlanStepOverBreakpoint.h */,
+ 260C847410F50EFC00BB2B04 /* ThreadPlanStepOverBreakpoint.cpp */,
+ 260C848410F50F0A00BB2B04 /* ThreadPlanStepRange.h */,
+ 260C847610F50EFC00BB2B04 /* ThreadPlanStepRange.cpp */,
+ 4C43DF8511069BFD00E55CBF /* ThreadPlanStepInRange.h */,
+ 4C43DF8911069C3200E55CBF /* ThreadPlanStepInRange.cpp */,
+ 4C43DF8611069BFD00E55CBF /* ThreadPlanStepOverRange.h */,
+ 4C43DF8A11069C3200E55CBF /* ThreadPlanStepOverRange.cpp */,
+ 4CAFCE001101216B00CA63DB /* ThreadPlanRunToAddress.h */,
+ 4CAFCE031101218900CA63DB /* ThreadPlanRunToAddress.cpp */,
+ 260C848310F50F0A00BB2B04 /* ThreadPlanStepThrough.h */,
+ 260C847510F50EFC00BB2B04 /* ThreadPlanStepThrough.cpp */,
+ 4CEDAED311754F5E00E875A6 /* ThreadPlanStepUntil.h */,
+ 2660D9FE11922A7F00958FBD /* ThreadPlanStepUntil.cpp */,
+ 4C00986F11500B4300F316B0 /* UnixSignals.h */,
+ 4C00987011500B4300F316B0 /* UnixSignals.cpp */,
+ 26E3EEBD11A9870400FBADB6 /* Unwind.h */,
+ );
+ name = Target;
+ sourceTree = "<group>";
+ };
+ 26BC7EE510F1B88100F91463 /* MacOSX */ = {
+ isa = PBXGroup;
+ children = (
+ 26BC7EED10F1B8AD00F91463 /* CFCBundle.cpp */,
+ 26BC7EEE10F1B8AD00F91463 /* CFCBundle.h */,
+ 26BC7EEF10F1B8AD00F91463 /* CFCData.cpp */,
+ 26BC7EF010F1B8AD00F91463 /* CFCData.h */,
+ 26BC7EF110F1B8AD00F91463 /* CFCMutableArray.cpp */,
+ 26BC7EF210F1B8AD00F91463 /* CFCMutableArray.h */,
+ 26BC7EF310F1B8AD00F91463 /* CFCMutableDictionary.cpp */,
+ 26BC7EF410F1B8AD00F91463 /* CFCMutableDictionary.h */,
+ 26BC7EF510F1B8AD00F91463 /* CFCMutableSet.cpp */,
+ 26BC7EF610F1B8AD00F91463 /* CFCMutableSet.h */,
+ 26BC7EF710F1B8AD00F91463 /* CFCReleaser.h */,
+ 26BC7EF810F1B8AD00F91463 /* CFCString.cpp */,
+ 26BC7EF910F1B8AD00F91463 /* CFCString.h */,
+ 26BC7EE710F1B88F00F91463 /* Condition.cpp */,
+ 26BC7EE810F1B88F00F91463 /* Host.mm */,
+ 26BC7EE910F1B88F00F91463 /* Mutex.cpp */,
+ 2689B0B5113EE47E00A4AEDB /* Symbols.cpp */,
+ 26B4E28B112F5DCD00AB3F64 /* TimeValue.cpp */,
+ );
+ name = MacOSX;
+ sourceTree = "<group>";
+ };
+ 26C9DF02113C5B80006B0F94 /* Include */ = {
+ isa = PBXGroup;
+ children = (
+ 26C9DF03113C5B93006B0F94 /* lldb */,
+ );
+ name = Include;
+ sourceTree = "<group>";
+ };
+ 26F5C22410F3D950009D5894 /* Tools */ = {
+ isa = PBXGroup;
+ children = (
+ 265E9BE0115C2B8500D0DCCB /* debugserver */,
+ 26F5C22510F3D956009D5894 /* Driver */,
+ );
+ name = Tools;
+ sourceTree = "<group>";
+ usesTabs = 0;
+ };
+ 26F5C22510F3D956009D5894 /* Driver */ = {
+ isa = PBXGroup;
+ children = (
+ 26F5C27210F3D9E4009D5894 /* lldb-Info.plist */,
+ 26F5C27410F3D9E4009D5894 /* Driver.h */,
+ 26F5C27310F3D9E4009D5894 /* Driver.cpp */,
+ 26F5C27610F3D9E4009D5894 /* IOChannel.h */,
+ 26F5C27510F3D9E4009D5894 /* IOChannel.cpp */,
+ );
+ name = Driver;
+ sourceTree = "<group>";
+ };
+ 26F5C32810F3DF7D009D5894 /* Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 26F5C39010F3FA26009D5894 /* CoreFoundation.framework */,
+ 265ABF6210F42EE900531910 /* DebugSymbols.framework */,
+ 260C876910F538E700BB2B04 /* Foundation.framework */,
+ 26F5C32A10F3DFDD009D5894 /* libedit.dylib */,
+ 26F5C37410F3F61B009D5894 /* libobjc.dylib */,
+ 26F5C32410F3DF23009D5894 /* libpython2.6.dylib */,
+ 26F5C32B10F3DFDD009D5894 /* libtermcap.dylib */,
+ );
+ name = Libraries;
+ sourceTree = "<group>";
+ usesTabs = 0;
+ };
+ 493C63D711891A8000914D5E /* ABI */ = {
+ isa = PBXGroup;
+ children = (
+ 497650CD11A21BD8008DDB57 /* MacOSX-i386 */,
+ 493C63EA11891FCD00914D5E /* SysV-x86_64 */,
+ );
+ name = ABI;
+ sourceTree = "<group>";
+ };
+ 493C63EA11891FCD00914D5E /* SysV-x86_64 */ = {
+ isa = PBXGroup;
+ children = (
+ 493C63F11189203300914D5E /* ABISysV_x86_64.cpp */,
+ 493C63F01189203300914D5E /* ABISysV_x86_64.h */,
+ );
+ name = "SysV-x86_64";
+ sourceTree = "<group>";
+ };
+ 497650CD11A21BD8008DDB57 /* MacOSX-i386 */ = {
+ isa = PBXGroup;
+ children = (
+ 497650CE11A21BEE008DDB57 /* ABIMacOSX_i386.cpp */,
+ 497650CF11A21BEE008DDB57 /* ABIMacOSX_i386.h */,
+ );
+ name = "MacOSX-i386";
+ sourceTree = "<group>";
+ };
+ 4CEE62F71145F1C70064CF93 /* GDB Remote */ = {
+ isa = PBXGroup;
+ children = (
+ 26FE25231146CADE00F4085A /* GDBRemoteCommunication.h */,
+ 26FE25221146CADE00F4085A /* GDBRemoteCommunication.cpp */,
+ 261E18CC1148966100BADCD3 /* GDBRemoteRegisterContext.h */,
+ 261E18CD1148966100BADCD3 /* GDBRemoteRegisterContext.cpp */,
+ 4CEE62FB1145F2130064CF93 /* ProcessGDBRemote.h */,
+ 4CEE62FA1145F2130064CF93 /* ProcessGDBRemote.cpp */,
+ 4CEE62FD1145F2130064CF93 /* ProcessGDBRemoteLog.h */,
+ 4CEE62FC1145F2130064CF93 /* ProcessGDBRemoteLog.cpp */,
+ 4CEE62FF1145F2130064CF93 /* ThreadGDBRemote.h */,
+ 4CEE62FE1145F2130064CF93 /* ThreadGDBRemote.cpp */,
+ );
+ name = "GDB Remote";
+ path = ../../..;
+ sourceTree = "<group>";
+ };
+ 9654F79F1197DA3F00F72B43 /* libunwind */ = {
+ isa = PBXGroup;
+ children = (
+ 9654F7A01197DA3F00F72B43 /* include */,
+ 9654F7A51197DA3F00F72B43 /* src */,
+ );
+ name = libunwind;
+ path = Utility/libunwind;
+ sourceTree = "<group>";
+ };
+ 9654F7A01197DA3F00F72B43 /* include */ = {
+ isa = PBXGroup;
+ children = (
+ 9654F7A11197DA3F00F72B43 /* libunwind.h */,
+ 9654F7A21197DA3F00F72B43 /* mach-o */,
+ 9654F7A41197DA3F00F72B43 /* unwind.h */,
+ );
+ path = include;
+ sourceTree = "<group>";
+ };
+ 9654F7A21197DA3F00F72B43 /* mach-o */ = {
+ isa = PBXGroup;
+ children = (
+ 9654F7A31197DA3F00F72B43 /* compact_unwind_encoding.h */,
+ );
+ path = "mach-o";
+ sourceTree = "<group>";
+ };
+ 9654F7A51197DA3F00F72B43 /* src */ = {
+ isa = PBXGroup;
+ children = (
+ 9654F7A61197DA3F00F72B43 /* AddressSpace.hpp */,
+ 9654F7A71197DA3F00F72B43 /* ArchDefaultUnwinder.hpp */,
+ 9654F7A81197DA3F00F72B43 /* AssemblyInstructions.hpp */,
+ 9654F7A91197DA3F00F72B43 /* AssemblyParser.hpp */,
+ 9654F7AA1197DA3F00F72B43 /* CompactUnwinder.hpp */,
+ 9654F7AB1197DA3F00F72B43 /* dwarf2.h */,
+ 9654F7AC1197DA3F00F72B43 /* DwarfInstructions.hpp */,
+ 9654F7AD1197DA3F00F72B43 /* DwarfParser.hpp */,
+ 9654F7AE1197DA3F00F72B43 /* FileAbstraction.hpp */,
+ 9654F7AF1197DA3F00F72B43 /* InternalMacros.h */,
+ 9654F7B21197DA3F00F72B43 /* libunwind_priv.h */,
+ 9654F7B31197DA3F00F72B43 /* libuwind.cxx */,
+ 9654F7B41197DA3F00F72B43 /* Registers.hpp */,
+ 9654F7B51197DA3F00F72B43 /* Registers.s */,
+ 9654F7B61197DA3F00F72B43 /* RemoteDebuggerDummyUnwinder.hpp */,
+ 9654F7B71197DA3F00F72B43 /* RemoteProcInfo.hpp */,
+ 9654F7B81197DA3F00F72B43 /* RemoteRegisterMap.hpp */,
+ 9654F7B91197DA3F00F72B43 /* RemoteUnwindProfile.h */,
+ 9654F7BA1197DA3F00F72B43 /* unw_getcontext.s */,
+ 9654F7BD1197DA3F00F72B43 /* UnwindCursor.hpp */,
+ );
+ path = src;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 26680202115FD0ED008E1FE4 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 26680219115FD13D008E1FE4 /* SBBreakpoint.h in Headers */,
+ 2668021A115FD13D008E1FE4 /* SBBreakpointLocation.h in Headers */,
+ 2668021B115FD13D008E1FE4 /* SBBroadcaster.h in Headers */,
+ 2668021C115FD13D008E1FE4 /* SBCommandContext.h in Headers */,
+ 2668021D115FD13D008E1FE4 /* SBCommandInterpreter.h in Headers */,
+ 2668021E115FD13D008E1FE4 /* SBCommandReturnObject.h in Headers */,
+ 2668021F115FD13D008E1FE4 /* SBCommunication.h in Headers */,
+ 26680220115FD13D008E1FE4 /* SBDebugger.h in Headers */,
+ 26680221115FD13D008E1FE4 /* SBDefines.h in Headers */,
+ 26680222115FD13D008E1FE4 /* SBError.h in Headers */,
+ 26680223115FD13D008E1FE4 /* SBEvent.h in Headers */,
+ 26680224115FD13D008E1FE4 /* SBFileSpec.h in Headers */,
+ 26680225115FD13D008E1FE4 /* SBFrame.h in Headers */,
+ 26680227115FD13D008E1FE4 /* SBListener.h in Headers */,
+ 2668022A115FD13D008E1FE4 /* SBProcess.h in Headers */,
+ 2668022B115FD13D008E1FE4 /* SBSourceManager.h in Headers */,
+ 2668022C115FD13D008E1FE4 /* SBTarget.h in Headers */,
+ 2668022E115FD13D008E1FE4 /* SBThread.h in Headers */,
+ 2668020E115FD12C008E1FE4 /* lldb-defines.h in Headers */,
+ 2668020F115FD12C008E1FE4 /* lldb-enumerations.h in Headers */,
+ 26680214115FD12C008E1FE4 /* lldb-types.h in Headers */,
+ 26DE1E6B11616C2E00A093E2 /* lldb-forward-rtti.h in Headers */,
+ 26DE1E6C11616C2E00A093E2 /* lldb-forward.h in Headers */,
+ 26DE204111618AB900A093E2 /* SBSymbolContext.h in Headers */,
+ 26DE204311618ACA00A093E2 /* SBAddress.h in Headers */,
+ 26DE204F11618E9800A093E2 /* SBModule.h in Headers */,
+ 26DE205311618FAC00A093E2 /* SBFunction.h in Headers */,
+ 26DE205511618FB800A093E2 /* SBCompileUnit.h in Headers */,
+ 26DE205711618FC500A093E2 /* SBBlock.h in Headers */,
+ 26DE205911618FE700A093E2 /* SBLineEntry.h in Headers */,
+ 26DE205B11618FF600A093E2 /* SBSymbol.h in Headers */,
+ 9A19A6AF1163BBB200E0D453 /* SBValue.h in Headers */,
+ 2617447A11685869005ADD65 /* SBType.h in Headers */,
+ 9A357583116CFDEE00E8ED2F /* SBValueList.h in Headers */,
+ 9A357671116E7B5200E8ED2F /* SBStringList.h in Headers */,
+ 9A3576A8116E9AB700E8ED2F /* SBHostOS.h in Headers */,
+ 9AC7038E117674FB0086C050 /* SBInstruction.h in Headers */,
+ 9AC70390117675270086C050 /* SBInstructionList.h in Headers */,
+ 26B42B1F1187A92B0079C8C8 /* lldb-include.h in Headers */,
+ 26B42C4D1187ABA50079C8C8 /* LLDB.h in Headers */,
+ 9AA69DAF118A023300D753A0 /* SBInputReader.h in Headers */,
+ 49F1A74A11B338AE003ED505 /* ClangExpressionDeclMap.h in Headers */,
+ 49D7072711B5AD03001AD875 /* ClangASTSource.h in Headers */,
+ 4CA9637C11B6E99A00780E28 /* CommandObjectApropos.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 26680206115FD0ED008E1FE4 /* LLDB */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2668020B115FD0EE008E1FE4 /* Build configuration list for PBXNativeTarget "LLDB" */;
+ buildPhases = (
+ 26D5B06111B07468009A862E /* Build llvm and clang */,
+ 26D5B06311B074CF009A862E /* Build swig wrapper classes */,
+ 26680202115FD0ED008E1FE4 /* Headers */,
+ 26680203115FD0ED008E1FE4 /* Resources */,
+ 26680204115FD0ED008E1FE4 /* Sources */,
+ 26680205115FD0ED008E1FE4 /* Frameworks */,
+ 9A19ACE2116563A700E0D453 /* Finish swig wrapper classes (lldb) */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 262CFC7211A450CB00946C6C /* PBXTargetDependency */,
+ );
+ name = LLDB;
+ productName = LLDB;
+ productReference = 26680207115FD0ED008E1FE4 /* LLDB.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ 26F5C26910F3D9A4009D5894 /* lldb-tool */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 26F5C26E10F3D9C5009D5894 /* Build configuration list for PBXNativeTarget "lldb-tool" */;
+ buildPhases = (
+ 26F5C26710F3D9A4009D5894 /* Sources */,
+ 26F5C26810F3D9A4009D5894 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 26CE0610115C438C0022F371 /* PBXTargetDependency */,
+ 266803621160110D008E1FE4 /* PBXTargetDependency */,
+ );
+ name = "lldb-tool";
+ productName = lldb;
+ productReference = 26F5C26A10F3D9A4009D5894 /* lldb */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "lldb" */;
+ compatibilityVersion = "Xcode 3.1";
+ hasScannedForEncodings = 1;
+ mainGroup = 08FB7794FE84155DC02AAC07 /* lldb */;
+ projectDirPath = "";
+ projectReferences = (
+ {
+ ProductGroup = 265E9BE2115C2BAA00D0DCCB /* Products */;
+ ProjectRef = 265E9BE1115C2BAA00D0DCCB /* debugserver.xcodeproj */;
+ },
+ );
+ projectRoot = "";
+ targets = (
+ 26F5C26910F3D9A4009D5894 /* lldb-tool */,
+ 26680206115FD0ED008E1FE4 /* LLDB */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+ 26CE05A0115C31E50022F371 /* debugserver */ = {
+ isa = PBXReferenceProxy;
+ fileType = "compiled.mach-o.executable";
+ path = debugserver;
+ remoteRef = 26CE059F115C31E50022F371 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 26680203115FD0ED008E1FE4 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 262CFC7711A4510000946C6C /* debugserver in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 26D5B06111B07468009A862E /* Build llvm and clang */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(LLVM_BUILD_DIR)",
+ "$(SRCROOT)/scripts/build-llvm.pl",
+ );
+ name = "Build llvm and clang";
+ outputPaths = (
+ "$(CONFIGURATION_BUILD_DIR)/libEnhancedDisassembly.dylib",
+ "$(LLVM_BUILD_DIR)/libllvmclang.a",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "perl $SRCROOT/scripts/build-llvm.pl";
+ };
+ 26D5B06311B074CF009A862E /* Build swig wrapper classes */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/scripts/lldb.swig",
+ "$(SRCROOT)/source/LLDBWrapPython.cpp",
+ );
+ name = "Build swig wrapper classes";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "sh $SRCROOT/scripts/build-swig-wrapper-classes.sh\n";
+ };
+ 9A19ACE2116563A700E0D453 /* Finish swig wrapper classes (lldb) */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/lldb.py",
+ "$(SRCROOT)/source/Interpreter/embedded_interpreter.py",
+ "$(SRCROOT)/scripts/Python/LLDBWrapPython.o",
+ );
+ name = "Finish swig wrapper classes (lldb)";
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/LLDB.framework/Resources/lldb.py",
+ "$(BUILT_PRODUCTS_DIR)/LLDB.framework/Resources/_lldb.so",
+ "$(BUILT_PRODUCTS_DIR)/LLDB.framework/Resources/embedded_interpreter.py",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "sh $SRCROOT/scripts/finish-swig-wrapper-classes.sh";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 26680204115FD0ED008E1FE4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 26D5B06511B07550009A862E /* StoppointCallbackContext.cpp in Sources */,
+ 26D5B06611B07550009A862E /* Breakpoint.cpp in Sources */,
+ 26D5B06711B07550009A862E /* BreakpointID.cpp in Sources */,
+ 26D5B06811B07550009A862E /* BreakpointIDList.cpp in Sources */,
+ 26D5B06911B07550009A862E /* BreakpointList.cpp in Sources */,
+ 26D5B06A11B07550009A862E /* BreakpointLocation.cpp in Sources */,
+ 26D5B06B11B07550009A862E /* BreakpointLocationCollection.cpp in Sources */,
+ 26D5B06C11B07550009A862E /* BreakpointLocationList.cpp in Sources */,
+ 26D5B06D11B07550009A862E /* BreakpointOptions.cpp in Sources */,
+ 26D5B06E11B07550009A862E /* BreakpointResolver.cpp in Sources */,
+ 26D5B06F11B07550009A862E /* BreakpointSite.cpp in Sources */,
+ 26D5B07011B07550009A862E /* BreakpointSiteList.cpp in Sources */,
+ 26D5B07111B07550009A862E /* SearchFilter.cpp in Sources */,
+ 26D5B07211B07550009A862E /* Stoppoint.cpp in Sources */,
+ 26D5B07311B07550009A862E /* StoppointLocation.cpp in Sources */,
+ 26D5B07411B07550009A862E /* WatchpointLocation.cpp in Sources */,
+ 26D5B07511B07550009A862E /* CommandObjectAlias.cpp in Sources */,
+ 26D5B07611B07550009A862E /* CommandObjectAppend.cpp in Sources */,
+ 26D5B07711B07550009A862E /* CommandObjectBreakpoint.cpp in Sources */,
+ 26D5B07811B07550009A862E /* CommandObjectDelete.cpp in Sources */,
+ 26D5B07911B07550009A862E /* CommandObjectDisassemble.cpp in Sources */,
+ 26D5B07A11B07550009A862E /* CommandObjectExpression.cpp in Sources */,
+ 26D5B07B11B07550009A862E /* CommandObjectFile.cpp in Sources */,
+ 26D5B07C11B07550009A862E /* CommandObjectHelp.cpp in Sources */,
+ 26D5B07D11B07550009A862E /* CommandObjectImage.cpp in Sources */,
+ 26D5B07E11B07550009A862E /* CommandObjectInfo.cpp in Sources */,
+ 26D5B07F11B07550009A862E /* CommandObjectMemory.cpp in Sources */,
+ 26D5B08011B07550009A862E /* CommandObjectProcess.cpp in Sources */,
+ 26D5B08111B07550009A862E /* CommandObjectQuit.cpp in Sources */,
+ 26D5B08211B07550009A862E /* CommandObjectRegister.cpp in Sources */,
+ 26D5B08311B07550009A862E /* CommandObjectScript.cpp in Sources */,
+ 26D5B08411B07550009A862E /* CommandObjectSelect.cpp in Sources */,
+ 26D5B08511B07550009A862E /* CommandObjectSet.cpp in Sources */,
+ 26D5B08611B07550009A862E /* CommandObjectSettings.cpp in Sources */,
+ 26D5B08711B07550009A862E /* CommandObjectShow.cpp in Sources */,
+ 26D5B08811B07550009A862E /* CommandObjectSource.cpp in Sources */,
+ 26D5B08911B07550009A862E /* CommandObjectSourceFile.cpp in Sources */,
+ 26D5B08A11B07550009A862E /* CommandObjectStatus.cpp in Sources */,
+ 26D5B08B11B07550009A862E /* CommandObjectSyntax.cpp in Sources */,
+ 26D5B08C11B07550009A862E /* CommandObjectThread.cpp in Sources */,
+ 26D5B08D11B07550009A862E /* CommandObjectVariable.cpp in Sources */,
+ 26D5B08E11B07550009A862E /* Address.cpp in Sources */,
+ 26D5B08F11B07550009A862E /* AddressRange.cpp in Sources */,
+ 26D5B09011B07550009A862E /* ArchSpec.cpp in Sources */,
+ 26D5B09111B07550009A862E /* Args.cpp in Sources */,
+ 26D5B09211B07550009A862E /* Broadcaster.cpp in Sources */,
+ 26D5B09311B07550009A862E /* Communication.cpp in Sources */,
+ 26D5B09411B07550009A862E /* Connection.cpp in Sources */,
+ 26D5B09511B07550009A862E /* ConnectionFileDescriptor.cpp in Sources */,
+ 26D5B09611B07550009A862E /* DataExtractor.cpp in Sources */,
+ 26D5B09711B07550009A862E /* DataBufferHeap.cpp in Sources */,
+ 26D5B09811B07550009A862E /* DataBufferMemoryMap.cpp in Sources */,
+ 26D5B09911B07550009A862E /* lldb.cpp in Sources */,
+ 26D5B09A11B07550009A862E /* lldb-log.cpp in Sources */,
+ 26D5B09B11B07550009A862E /* Disassembler.cpp in Sources */,
+ 26D5B09C11B07550009A862E /* DynamicLoader.cpp in Sources */,
+ 26D5B09D11B07550009A862E /* Error.cpp in Sources */,
+ 26D5B09E11B07550009A862E /* Event.cpp in Sources */,
+ 26D5B09F11B07550009A862E /* FileSpec.cpp in Sources */,
+ 26D5B0A011B07550009A862E /* FileSpecList.cpp in Sources */,
+ 26D5B0A111B07550009A862E /* Flags.cpp in Sources */,
+ 26D5B0A211B07550009A862E /* Language.cpp in Sources */,
+ 26D5B0A311B07550009A862E /* Listener.cpp in Sources */,
+ 26D5B0A411B07550009A862E /* Log.cpp in Sources */,
+ 26D5B0A511B07550009A862E /* Mangled.cpp in Sources */,
+ 26D5B0A611B07550009A862E /* Module.cpp in Sources */,
+ 26D5B0A711B07550009A862E /* ModuleChild.cpp in Sources */,
+ 26D5B0A811B07550009A862E /* ModuleList.cpp in Sources */,
+ 26D5B0A911B07550009A862E /* Options.cpp in Sources */,
+ 26D5B0AA11B07550009A862E /* PluginManager.cpp in Sources */,
+ 26D5B0AB11B07550009A862E /* RegularExpression.cpp in Sources */,
+ 26D5B0AC11B07550009A862E /* Scalar.cpp in Sources */,
+ 26D5B0AD11B07550009A862E /* Section.cpp in Sources */,
+ 26D5B0AE11B07550009A862E /* SourceManager.cpp in Sources */,
+ 26D5B0AF11B07550009A862E /* State.cpp in Sources */,
+ 26D5B0B011B07550009A862E /* Stream.cpp in Sources */,
+ 26D5B0B111B07550009A862E /* StreamFile.cpp in Sources */,
+ 26D5B0B211B07550009A862E /* StreamString.cpp in Sources */,
+ 26D5B0B311B07550009A862E /* ConstString.cpp in Sources */,
+ 26D5B0B411B07550009A862E /* Timer.cpp in Sources */,
+ 26D5B0B511B07550009A862E /* TTYState.cpp in Sources */,
+ 26D5B0B611B07550009A862E /* UserID.cpp in Sources */,
+ 26D5B0B711B07550009A862E /* Value.cpp in Sources */,
+ 26D5B0B811B07550009A862E /* ValueObject.cpp in Sources */,
+ 26D5B0B911B07550009A862E /* ValueObjectChild.cpp in Sources */,
+ 26D5B0BA11B07550009A862E /* ValueObjectList.cpp in Sources */,
+ 26D5B0BB11B07550009A862E /* ValueObjectVariable.cpp in Sources */,
+ 26D5B0BC11B07550009A862E /* VMRange.cpp in Sources */,
+ 26D5B0BD11B07550009A862E /* ClangExpression.cpp in Sources */,
+ 26D5B0BE11B07550009A862E /* ClangExpressionVariable.cpp in Sources */,
+ 26D5B0BF11B07550009A862E /* ClangStmtVisitor.cpp in Sources */,
+ 26D5B0C011B07550009A862E /* DWARFExpression.cpp in Sources */,
+ 26D5B0C111B07550009A862E /* Condition.cpp in Sources */,
+ 26D5B0C211B07550009A862E /* Host.mm in Sources */,
+ 26D5B0C311B07550009A862E /* Mutex.cpp in Sources */,
+ 26D5B0C411B07550009A862E /* CFCBundle.cpp in Sources */,
+ 26D5B0C511B07550009A862E /* CFCData.cpp in Sources */,
+ 26D5B0C611B07550009A862E /* CFCMutableArray.cpp in Sources */,
+ 26D5B0C711B07550009A862E /* CFCMutableDictionary.cpp in Sources */,
+ 26D5B0C811B07550009A862E /* CFCMutableSet.cpp in Sources */,
+ 26D5B0C911B07550009A862E /* CFCString.cpp in Sources */,
+ 26D5B0CA11B07550009A862E /* CommandContext.cpp in Sources */,
+ 26D5B0CB11B07550009A862E /* CommandInterpreter.cpp in Sources */,
+ 26D5B0CC11B07550009A862E /* CommandObject.cpp in Sources */,
+ 26D5B0CD11B07550009A862E /* CommandReturnObject.cpp in Sources */,
+ 26D5B0CE11B07550009A862E /* StateVariable.cpp in Sources */,
+ 26D5B0CF11B07550009A862E /* ScriptInterpreterPython.cpp in Sources */,
+ 26D5B0D011B07550009A862E /* Block.cpp in Sources */,
+ 26D5B0D111B07550009A862E /* ClangASTContext.cpp in Sources */,
+ 26D5B0D211B07550009A862E /* CompileUnit.cpp in Sources */,
+ 26D5B0D311B07550009A862E /* Declaration.cpp in Sources */,
+ 26D5B0D411B07550009A862E /* DWARFCallFrameInfo.cpp in Sources */,
+ 26D5B0D511B07550009A862E /* Function.cpp in Sources */,
+ 26D5B0D611B07550009A862E /* LineEntry.cpp in Sources */,
+ 26D5B0D711B07550009A862E /* LineTable.cpp in Sources */,
+ 26D5B0D811B07550009A862E /* Symbol.cpp in Sources */,
+ 26D5B0D911B07550009A862E /* SymbolContext.cpp in Sources */,
+ 26D5B0DA11B07550009A862E /* SymbolFile.cpp in Sources */,
+ 26D5B0DB11B07550009A862E /* SymbolVendor.mm in Sources */,
+ 26D5B0DC11B07550009A862E /* Symtab.cpp in Sources */,
+ 26D5B0DD11B07550009A862E /* Type.cpp in Sources */,
+ 26D5B0DE11B07550009A862E /* TypeList.cpp in Sources */,
+ 26D5B0DF11B07550009A862E /* Variable.cpp in Sources */,
+ 26D5B0E011B07550009A862E /* VariableList.cpp in Sources */,
+ 26D5B0E111B07550009A862E /* ExecutionContext.cpp in Sources */,
+ 26D5B0E211B07550009A862E /* Process.cpp in Sources */,
+ 26D5B0E311B07550009A862E /* RegisterContext.cpp in Sources */,
+ 26D5B0E411B07550009A862E /* StackFrame.cpp in Sources */,
+ 26D5B0E511B07550009A862E /* StackFrameList.cpp in Sources */,
+ 26D5B0E611B07550009A862E /* StackID.cpp in Sources */,
+ 26D5B0E711B07550009A862E /* Target.cpp in Sources */,
+ 26D5B0E811B07550009A862E /* TargetList.cpp in Sources */,
+ 26D5B0E911B07550009A862E /* Thread.cpp in Sources */,
+ 26D5B0EA11B07550009A862E /* ThreadList.cpp in Sources */,
+ 26D5B0EB11B07550009A862E /* ThreadPlan.cpp in Sources */,
+ 26D5B0EC11B07550009A862E /* ObjectFile.cpp in Sources */,
+ 26D5B0ED11B07550009A862E /* ThreadPlanContinue.cpp in Sources */,
+ 26D5B0EE11B07550009A862E /* ThreadPlanBase.cpp in Sources */,
+ 26D5B0EF11B07550009A862E /* ThreadPlanStepInstruction.cpp in Sources */,
+ 26D5B0F011B07550009A862E /* ThreadPlanStepOut.cpp in Sources */,
+ 26D5B0F111B07550009A862E /* ThreadPlanStepOverBreakpoint.cpp in Sources */,
+ 26D5B0F211B07550009A862E /* ThreadPlanStepThrough.cpp in Sources */,
+ 26D5B0F311B07550009A862E /* ThreadPlanStepRange.cpp in Sources */,
+ 26D5B0F411B07550009A862E /* DynamicLoaderMacOSXDYLD.cpp in Sources */,
+ 26D5B0F511B07550009A862E /* DynamicLoaderMacOSXDYLDLog.cpp in Sources */,
+ 26D5B0F611B07550009A862E /* ObjectContainerUniversalMachO.cpp in Sources */,
+ 26D5B0F711B07550009A862E /* ObjectFileELF.cpp in Sources */,
+ 26D5B0F811B07550009A862E /* ObjectFileMachO.cpp in Sources */,
+ 26D5B0F911B07550009A862E /* MachException.cpp in Sources */,
+ 26D5B0FA11B07550009A862E /* MachTask.cpp in Sources */,
+ 26D5B0FB11B07550009A862E /* MachThreadContext_arm.cpp in Sources */,
+ 26D5B0FC11B07550009A862E /* MachThreadContext_i386.cpp in Sources */,
+ 26D5B0FD11B07550009A862E /* MachThreadContext_x86_64.cpp in Sources */,
+ 26D5B0FE11B07550009A862E /* MachVMMemory.cpp in Sources */,
+ 26D5B0FF11B07550009A862E /* MachVMRegion.cpp in Sources */,
+ 26D5B10011B07550009A862E /* ProcessControl-mig.defs in Sources */,
+ 26D5B10111B07550009A862E /* ProcessMacOSX.cpp in Sources */,
+ 26D5B10211B07550009A862E /* ProcessMacOSXLog.cpp in Sources */,
+ 26D5B10311B07550009A862E /* RegisterContextMach_arm.cpp in Sources */,
+ 26D5B10411B07550009A862E /* RegisterContextMach_i386.cpp in Sources */,
+ 26D5B10511B07550009A862E /* RegisterContextMach_x86_64.cpp in Sources */,
+ 26D5B10611B07550009A862E /* ThreadMacOSX.cpp in Sources */,
+ 26D5B10711B07550009A862E /* DWARFAbbreviationDeclaration.cpp in Sources */,
+ 26D5B10811B07550009A862E /* DWARFCompileUnit.cpp in Sources */,
+ 26D5B10911B07550009A862E /* DWARFDebugAbbrev.cpp in Sources */,
+ 26D5B10A11B07550009A862E /* DWARFDebugAranges.cpp in Sources */,
+ 26D5B10B11B07550009A862E /* DWARFDebugArangeSet.cpp in Sources */,
+ 26D5B10C11B07550009A862E /* DWARFDebugInfo.cpp in Sources */,
+ 26D5B10D11B07550009A862E /* DWARFDebugInfoEntry.cpp in Sources */,
+ 26D5B10E11B07550009A862E /* DWARFDebugLine.cpp in Sources */,
+ 26D5B10F11B07550009A862E /* DWARFDebugMacinfo.cpp in Sources */,
+ 26D5B11011B07550009A862E /* DWARFDebugMacinfoEntry.cpp in Sources */,
+ 26D5B11111B07550009A862E /* DWARFDebugPubnames.cpp in Sources */,
+ 26D5B11211B07550009A862E /* DWARFDebugPubnamesSet.cpp in Sources */,
+ 26D5B11311B07550009A862E /* DWARFDebugRanges.cpp in Sources */,
+ 26D5B11411B07550009A862E /* DWARFDefines.c in Sources */,
+ 26D5B11511B07550009A862E /* DWARFDIECollection.cpp in Sources */,
+ 26D5B11611B07550009A862E /* DWARFFormValue.cpp in Sources */,
+ 26D5B11711B07550009A862E /* DWARFLocationDescription.cpp in Sources */,
+ 26D5B11811B07550009A862E /* DWARFLocationList.cpp in Sources */,
+ 26D5B11911B07550009A862E /* SymbolFileDWARF.cpp in Sources */,
+ 26D5B11A11B07550009A862E /* SymbolFileDWARFDebugMap.cpp in Sources */,
+ 26D5B11B11B07550009A862E /* SymbolFileSymtab.cpp in Sources */,
+ 26D5B11C11B07550009A862E /* SymbolVendorMacOSX.cpp in Sources */,
+ 26D5B11D11B07550009A862E /* CommandObjectUnalias.cpp in Sources */,
+ 26D5B11E11B07550009A862E /* ScriptInterpreter.cpp in Sources */,
+ 26D5B11F11B07550009A862E /* BreakpointResolverAddress.cpp in Sources */,
+ 26D5B12011B07550009A862E /* BreakpointResolverFileLine.cpp in Sources */,
+ 26D5B12111B07550009A862E /* BreakpointResolverName.cpp in Sources */,
+ 26D5B12211B07550009A862E /* DisassemblerLLVM.cpp in Sources */,
+ 26D5B12311B07550009A862E /* ThreadPlanRunToAddress.cpp in Sources */,
+ 26D5B12411B07550009A862E /* ThreadPlanShouldStopHere.cpp in Sources */,
+ 26D5B12511B07550009A862E /* ThreadPlanStepInRange.cpp in Sources */,
+ 26D5B12611B07550009A862E /* ThreadPlanStepOverRange.cpp in Sources */,
+ 26D5B12711B07550009A862E /* CommandObjectLog.cpp in Sources */,
+ 26D5B12811B07550009A862E /* ValueObjectRegister.cpp in Sources */,
+ 26D5B12911B07550009A862E /* TimeValue.cpp in Sources */,
+ 26D5B12A11B07550009A862E /* UUID.cpp in Sources */,
+ 26D5B12B11B07550009A862E /* ScriptInterpreterNone.cpp in Sources */,
+ 26D5B12C11B07550009A862E /* CommandObjectCrossref.cpp in Sources */,
+ 26D5B12D11B07550009A862E /* CommandObjectMultiword.cpp in Sources */,
+ 26D5B12E11B07550009A862E /* CommandObjectRegexCommand.cpp in Sources */,
+ 26D5B12F11B07550009A862E /* Symbols.cpp in Sources */,
+ 26D5B13011B07550009A862E /* Debugger.cpp in Sources */,
+ 26D5B13111B07550009A862E /* ProcessGDBRemote.cpp in Sources */,
+ 26D5B13211B07550009A862E /* ProcessGDBRemoteLog.cpp in Sources */,
+ 26D5B13311B07550009A862E /* ThreadGDBRemote.cpp in Sources */,
+ 26D5B13411B07550009A862E /* GDBRemoteCommunication.cpp in Sources */,
+ 26D5B13511B07550009A862E /* GDBRemoteRegisterContext.cpp in Sources */,
+ 26D5B13611B07550009A862E /* UnixSignals.cpp in Sources */,
+ 26D5B13711B07550009A862E /* LogChannelDWARF.cpp in Sources */,
+ 26D5B13811B07550009A862E /* PseudoTerminal.cpp in Sources */,
+ 26D5B13911B07550009A862E /* LLDBWrapPython.cpp in Sources */,
+ 26D5B13A11B07550009A862E /* StringList.cpp in Sources */,
+ 26D5B13B11B07550009A862E /* CommandCompletions.cpp in Sources */,
+ 26D5B13C11B07550009A862E /* AddressResolver.cpp in Sources */,
+ 26D5B13D11B07550009A862E /* AddressResolverFileLine.cpp in Sources */,
+ 26D5B13E11B07550009A862E /* AddressResolverName.cpp in Sources */,
+ 26D5B13F11B07550009A862E /* ObjectContainerBSDArchive.cpp in Sources */,
+ 26D5B14011B07550009A862E /* CommandObjectBreakpointCommand.cpp in Sources */,
+ 26D5B14111B07550009A862E /* InputReader.cpp in Sources */,
+ 26D5B14211B07550009A862E /* CommandObjectFrame.cpp in Sources */,
+ 26D5B14311B07550009A862E /* ABISysV_x86_64.cpp in Sources */,
+ 26D5B14411B07550009A862E /* ABI.cpp in Sources */,
+ 26D5B14511B07550009A862E /* StringExtractor.cpp in Sources */,
+ 26D5B14611B07550009A862E /* ThreadPlanStepUntil.cpp in Sources */,
+ 26D5B14711B07550009A862E /* ThreadPlanCallFunction.cpp in Sources */,
+ 26D5B14811B07550009A862E /* ClangFunction.cpp in Sources */,
+ 26D5B14911B07550009A862E /* RecordingMemoryManager.cpp in Sources */,
+ 26D5B14A11B07550009A862E /* CommandObjectCall.cpp in Sources */,
+ 26D5B14B11B07550009A862E /* CommandObjectTarget.cpp in Sources */,
+ 26D5B14C11B07550009A862E /* PathMappingList.cpp in Sources */,
+ 26D5B14D11B07550009A862E /* StringExtractorGDBRemote.cpp in Sources */,
+ 26D5B14E11B07550009A862E /* MacOSXLibunwindCallbacks.cpp in Sources */,
+ 26D5B15011B07550009A862E /* Registers.s in Sources */,
+ 26D5B15111B07550009A862E /* unw_getcontext.s in Sources */,
+ 26D5B15211B07550009A862E /* LibUnwindRegisterContext.cpp in Sources */,
+ 26D5B15311B07550009A862E /* ABIMacOSX_i386.cpp in Sources */,
+ 26D5B15411B07550009A862E /* ObjCTrampolineHandler.cpp in Sources */,
+ 26D5B15511B07550009A862E /* Baton.cpp in Sources */,
+ 26D5B15611B07550009A862E /* CommandObjectArgs.cpp in Sources */,
+ 26D5B15711B07550009A862E /* ThreadPlanStepThroughObjCTrampoline.cpp in Sources */,
+ 26D5B15911B07550009A862E /* UnwindLibUnwind.cpp in Sources */,
+ 26D5B15A11B07550009A862E /* UnwindMacOSXFrameBackchain.cpp in Sources */,
+ 26D5B15B11B07550009A862E /* RegisterContextMacOSXFrameBackchain.cpp in Sources */,
+ 26D5B15C11B07550009A862E /* ObjCObjectPrinter.cpp in Sources */,
+ 26680324116005D9008E1FE4 /* SBThread.cpp in Sources */,
+ 26680326116005DB008E1FE4 /* SBTarget.cpp in Sources */,
+ 26680327116005DC008E1FE4 /* SBSourceManager.cpp in Sources */,
+ 26680328116005DE008E1FE4 /* SBProcess.cpp in Sources */,
+ 2668032A116005E0008E1FE4 /* SBListener.cpp in Sources */,
+ 2668032C116005E2008E1FE4 /* SBFrame.cpp in Sources */,
+ 2668032D116005E3008E1FE4 /* SBFileSpec.cpp in Sources */,
+ 2668032E116005E5008E1FE4 /* SBEvent.cpp in Sources */,
+ 2668032F116005E6008E1FE4 /* SBError.cpp in Sources */,
+ 26680330116005E7008E1FE4 /* SBDebugger.cpp in Sources */,
+ 26680331116005E9008E1FE4 /* SBCommunication.cpp in Sources */,
+ 26680332116005EA008E1FE4 /* SBCommandReturnObject.cpp in Sources */,
+ 26680333116005EC008E1FE4 /* SBCommandInterpreter.cpp in Sources */,
+ 26680334116005ED008E1FE4 /* SBCommandContext.cpp in Sources */,
+ 26680335116005EE008E1FE4 /* SBBroadcaster.cpp in Sources */,
+ 26680336116005EF008E1FE4 /* SBBreakpointLocation.cpp in Sources */,
+ 26680337116005F1008E1FE4 /* SBBreakpoint.cpp in Sources */,
+ 26DE204511618ADA00A093E2 /* SBAddress.cpp in Sources */,
+ 26DE204711618AED00A093E2 /* SBSymbolContext.cpp in Sources */,
+ 26DE204D11618E7A00A093E2 /* SBModule.cpp in Sources */,
+ 26DE205D1161901400A093E2 /* SBFunction.cpp in Sources */,
+ 26DE205F1161901B00A093E2 /* SBCompileUnit.cpp in Sources */,
+ 26DE20611161902700A093E2 /* SBBlock.cpp in Sources */,
+ 26DE20631161904200A093E2 /* SBLineEntry.cpp in Sources */,
+ 26DE20651161904E00A093E2 /* SBSymbol.cpp in Sources */,
+ 9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */,
+ 261744781168585B005ADD65 /* SBType.cpp in Sources */,
+ 9A35758E116CFE0F00E8ED2F /* SBValueList.cpp in Sources */,
+ 9A357673116E7B6400E8ED2F /* SBStringList.cpp in Sources */,
+ 9A3576AA116E9AC700E8ED2F /* SBHostOS.cpp in Sources */,
+ 9AC703AF117675410086C050 /* SBInstruction.cpp in Sources */,
+ 9AC703B1117675490086C050 /* SBInstructionList.cpp in Sources */,
+ 9AA69DB1118A024600D753A0 /* SBInputReader.cpp in Sources */,
+ 26D5B18E11B07979009A862E /* libuwind.cxx in Sources */,
+ 49F1A74611B3388F003ED505 /* ClangExpressionDeclMap.cpp in Sources */,
+ 49D7072911B5AD11001AD875 /* ClangASTSource.cpp in Sources */,
+ 4CA9637B11B6E99A00780E28 /* CommandObjectApropos.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 26F5C26710F3D9A4009D5894 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 26F5C27710F3D9E4009D5894 /* Driver.cpp in Sources */,
+ 26F5C27810F3D9E4009D5894 /* IOChannel.cpp in Sources */,
+ 9AA69DA61188F52100D753A0 /* PseudoTerminal.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 262CFC7211A450CB00946C6C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ name = debugserver;
+ targetProxy = 262CFC7111A450CB00946C6C /* PBXContainerItemProxy */;
+ };
+ 266803621160110D008E1FE4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 26680206115FD0ED008E1FE4 /* LLDB */;
+ targetProxy = 266803611160110D008E1FE4 /* PBXContainerItemProxy */;
+ };
+ 26CE0610115C438C0022F371 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ name = "lldb-debugserver";
+ targetProxy = 26CE060F115C438C0022F371 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB91F008733DB70010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = (
+ x86_64,
+ i386,
+ );
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ __STDC_CONSTANT_MACROS,
+ __STDC_LIMIT_MACROS,
+ LLDB_CONFIGURATION_DEBUG,
+ );
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PREBINDING = NO;
+ VALID_ARCHS = "x86_64 i386";
+ };
+ name = Debug;
+ };
+ 1DEB91F108733DB70010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = (
+ x86_64,
+ i386,
+ );
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ __STDC_CONSTANT_MACROS,
+ __STDC_LIMIT_MACROS,
+ LLDB_CONFIGURATION_RELEASE,
+ );
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ VALID_ARCHS = "x86_64 i386";
+ };
+ name = Release;
+ };
+ 26680209115FD0ED008E1FE4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 24;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 24;
+ EXPORTED_SYMBOLS_FILE = "resources/lldb-framework-exports";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
+ );
+ FRAMEWORK_VERSION = A;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_OBJC_GC = supported;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_VERSION = 4.2;
+ HEADER_SEARCH_PATHS = /usr/include/python2.6;
+ INFOPLIST_FILE = "resources/LLDB-Info.plist";
+ INSTALL_PATH = /Developer/Library/PrivateFrameworks;
+ LD_DYLIB_INSTALL_NAME = "@rpath/LLDB.framework/Versions/A/LLDB";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(LLVM_BUILD_DIR)",
+ );
+ LLVM_BUILD_DIR = "$(SRCROOT)/llvm";
+ LLVM_CONFIGURATION = Debug;
+ OTHER_CFLAGS = (
+ "-DFOR_DYLD=0",
+ "-DSUPPORT_REMOTE_UNWINDING",
+ );
+ OTHER_CPLUSPLUSFLAGS = (
+ "-Wglobal-constructors",
+ "$(OTHER_CFLAGS)",
+ );
+ OTHER_LDFLAGS = (
+ "-lllvmclang",
+ "-framework",
+ Foundation,
+ "-framework",
+ AppKit,
+ );
+ PREBINDING = NO;
+ PRODUCT_NAME = LLDB;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/include $(SRCROOT)/source/Host/macosx/cfcpp $(SRCROOT)/llvm/include $(SRCROOT)/llvm/tools/clang/include $(LLVM_BUILD_DIR)/llvm/include $(LLVM_BUILD_DIR)/llvm/tools/clang/include";
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 2668020A115FD0ED008E1FE4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 24;
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 24;
+ EXPORTED_SYMBOLS_FILE = "resources/lldb-framework-exports";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
+ );
+ FRAMEWORK_VERSION = A;
+ GCC_ENABLE_OBJC_GC = supported;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
+ GCC_VERSION = 4.2;
+ HEADER_SEARCH_PATHS = /usr/include/python2.6;
+ INFOPLIST_FILE = "resources/LLDB-Info.plist";
+ INSTALL_PATH = /Developer/Library/PrivateFrameworks;
+ LD_DYLIB_INSTALL_NAME = "@rpath/LLDB.framework/Versions/A/LLDB";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(LLVM_BUILD_DIR)",
+ );
+ LLVM_BUILD_DIR = "$(SRCROOT)/llvm";
+ LLVM_CONFIGURATION = Release;
+ OTHER_CFLAGS = (
+ "-DFOR_DYLD=0",
+ "-DSUPPORT_REMOTE_UNWINDING",
+ );
+ OTHER_CPLUSPLUSFLAGS = (
+ "-Wglobal-constructors",
+ "$(OTHER_CFLAGS)",
+ );
+ OTHER_LDFLAGS = (
+ "-lllvmclang",
+ "-framework",
+ Foundation,
+ "-framework",
+ AppKit,
+ );
+ PREBINDING = NO;
+ PRODUCT_NAME = LLDB;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/include $(SRCROOT)/source/Host/macosx/cfcpp $(SRCROOT)/llvm/include $(SRCROOT)/llvm/tools/clang/include $(LLVM_BUILD_DIR)/llvm/include $(LLVM_BUILD_DIR)/llvm/tools/clang/include";
+ VERSIONING_SYSTEM = "apple-generic";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 268A89B211963ECA00D953EB /* BuildAndIntegration */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = (
+ x86_64,
+ i386,
+ );
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ __STDC_CONSTANT_MACROS,
+ __STDC_LIMIT_MACROS,
+ LLDB_CONFIGURATION_BUILD_AND_INTEGRATION,
+ );
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ VALID_ARCHS = "x86_64 i386";
+ };
+ name = BuildAndIntegration;
+ };
+ 268A89B311963ECA00D953EB /* BuildAndIntegration */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = 24;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
+ );
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_VERSION = 4.2;
+ INFOPLIST_FILE = "lldb-Info.plist";
+ INSTALL_PATH = /Developer/usr/bin;
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
+ OTHER_LDFLAGS = (
+ "-sectcreate",
+ __TEXT,
+ __info_plist,
+ "$(PROJECT_DIR)/tools/driver/lldb-Info.plist",
+ "-Wl,-rpath,@loader_path/../../Library/PrivateFrameworks/",
+ );
+ PREBINDING = NO;
+ PRODUCT_NAME = lldb;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/include/lldb/Utility";
+ VERSIONING_SYSTEM = "apple-generic";
+ ZERO_LINK = NO;
+ };
+ name = BuildAndIntegration;
+ };
+ 268A89B511963ECA00D953EB /* BuildAndIntegration */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = 24;
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 24;
+ EXPORTED_SYMBOLS_FILE = "resources/lldb-framework-exports";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
+ );
+ FRAMEWORK_VERSION = A;
+ GCC_ENABLE_OBJC_GC = supported;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
+ GCC_VERSION = 4.2;
+ HEADER_SEARCH_PATHS = /usr/include/python2.6;
+ INFOPLIST_FILE = "resources/LLDB-Info.plist";
+ INSTALL_PATH = /Developer/Library/PrivateFrameworks;
+ LD_DYLIB_INSTALL_NAME = "@rpath/LLDB.framework/Versions/A/LLDB";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(LLVM_BUILD_DIR)",
+ );
+ LLVM_BUILD_DIR = "$(DERIVED_FILE_DIR)/llvm.build";
+ LLVM_CONFIGURATION = Release;
+ OTHER_CFLAGS = (
+ "-DFOR_DYLD=0",
+ "-DSUPPORT_REMOTE_UNWINDING",
+ );
+ OTHER_CPLUSPLUSFLAGS = (
+ "-Wglobal-constructors",
+ "$(OTHER_CFLAGS)",
+ );
+ OTHER_LDFLAGS = (
+ "-lllvmclang",
+ "-framework",
+ Foundation,
+ "-framework",
+ AppKit,
+ );
+ PREBINDING = NO;
+ PRODUCT_NAME = LLDB;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/include $(SRCROOT)/source/Host/macosx/cfcpp $(SRCROOT)/llvm/include $(SRCROOT)/llvm/tools/clang/include $(LLVM_BUILD_DIR)/llvm/include $(LLVM_BUILD_DIR)/llvm/tools/clang/include";
+ VERSIONING_SYSTEM = "apple-generic";
+ ZERO_LINK = NO;
+ };
+ name = BuildAndIntegration;
+ };
+ 26F5C26C10F3D9A5009D5894 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_IDENTITY = lldb_codesign;
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 24;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
+ );
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_VERSION = 4.2;
+ INFOPLIST_FILE = "lldb-Info.plist";
+ INSTALL_PATH = /Developer/usr/bin;
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
+ ONLY_ACTIVE_ARCH = YES;
+ OTHER_LDFLAGS = (
+ "-sectcreate",
+ __TEXT,
+ __info_plist,
+ "$(PROJECT_DIR)/tools/driver/lldb-Info.plist",
+ "-Wl,-rpath,@loader_path/",
+ );
+ PREBINDING = NO;
+ PRODUCT_NAME = lldb;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/include/lldb/Utility";
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 26F5C26D10F3D9A5009D5894 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = (
+ x86_64,
+ i386,
+ );
+ CODE_SIGN_IDENTITY = lldb_codesign;
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = 24;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
+ );
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_VERSION = 4.2;
+ INFOPLIST_FILE = "lldb-Info.plist";
+ INSTALL_PATH = /Developer/usr/bin;
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
+ OTHER_LDFLAGS = (
+ "-sectcreate",
+ __TEXT,
+ __info_plist,
+ "$(PROJECT_DIR)/tools/driver/lldb-Info.plist",
+ "-Wl,-rpath,@loader_path/../../Library/PrivateFrameworks/",
+ );
+ PREBINDING = NO;
+ PRODUCT_NAME = lldb;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/include/lldb/Utility";
+ VERSIONING_SYSTEM = "apple-generic";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "lldb" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB91F008733DB70010E9CD /* Debug */,
+ 1DEB91F108733DB70010E9CD /* Release */,
+ 268A89B211963ECA00D953EB /* BuildAndIntegration */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = BuildAndIntegration;
+ };
+ 2668020B115FD0EE008E1FE4 /* Build configuration list for PBXNativeTarget "LLDB" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 26680209115FD0ED008E1FE4 /* Debug */,
+ 2668020A115FD0ED008E1FE4 /* Release */,
+ 268A89B511963ECA00D953EB /* BuildAndIntegration */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = BuildAndIntegration;
+ };
+ 26F5C26E10F3D9C5009D5894 /* Build configuration list for PBXNativeTarget "lldb-tool" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 26F5C26C10F3D9A5009D5894 /* Debug */,
+ 26F5C26D10F3D9A5009D5894 /* Release */,
+ 268A89B311963ECA00D953EB /* BuildAndIntegration */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = BuildAndIntegration;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
diff --git a/lldb/lldb.xcworkspace/contents.xcworkspacedata b/lldb/lldb.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 00000000000..8995b415fd4
--- /dev/null
+++ b/lldb/lldb.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace>
+ <FileRef
+ path = "lldb.xcodeproj"
+ referenceStyle = "3">
+ </FileRef>
+ <Group
+ name = "Supporting Files">
+ <FileRef
+ path = "lldb.runcontext"
+ referenceStyle = "3">
+ </FileRef>
+ </Group>
+ <SmartGroup
+ name = "Run Contexts"
+ typeIdentifier = "com.apple.dt.document.run-context">
+ </SmartGroup>
+</Workspace>
diff --git a/lldb/resources/LLDB-Info.plist b/lldb/resources/LLDB-Info.plist
new file mode 100644
index 00000000000..922b8c169cc
--- /dev/null
+++ b/lldb/resources/LLDB-Info.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.${PRODUCT_NAME:rfc1034identifier}.framework</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>24</string>
+ <key>CFBundleName</key>
+ <string>${EXECUTABLE_NAME}</string>
+</dict>
+</plist>
diff --git a/lldb/resources/lldb-framework-exports b/lldb/resources/lldb-framework-exports
new file mode 100644
index 00000000000..174c1594056
--- /dev/null
+++ b/lldb/resources/lldb-framework-exports
@@ -0,0 +1,3 @@
+__ZN4lldb*
+__ZNK4lldb*
+_init_lldb
diff --git a/lldb/scripts/Python/build-swig-Python.sh b/lldb/scripts/Python/build-swig-Python.sh
new file mode 100755
index 00000000000..9dc4b991c4a
--- /dev/null
+++ b/lldb/scripts/Python/build-swig-Python.sh
@@ -0,0 +1,127 @@
+#!/bin/sh
+
+# build-swig-Python.sh
+
+
+debug_flag=$1
+
+if [ -n "$debug_flag" -a "$debug_flag" == "-debug" ]
+then
+ Debug=1
+else
+ Debug=0
+fi
+
+
+HEADER_FILES="${SRCROOT}/include/lldb/lldb-types.h"\
+" ${SRCROOT}/include/lldb/API/SBAddress.h"\
+" ${SRCROOT}/include/lldb/API/SBBlock.h"\
+" ${SRCROOT}/include/lldb/API/SBBreakpoint.h"\
+" ${SRCROOT}/include/lldb/API/SBBreakpointLocation.h"\
+" ${SRCROOT}/include/lldb/API/SBBroadcaster.h"\
+" ${SRCROOT}/include/lldb/API/SBCommandContext.h"\
+" ${SRCROOT}/include/lldb/API/SBCommandInterpreter.h"\
+" ${SRCROOT}/include/lldb/API/SBCommandReturnObject.h"\
+" ${SRCROOT}/include/lldb/API/SBCompileUnit.h"\
+" ${SRCROOT}/include/lldb/API/SBDebugger.h"\
+" ${SRCROOT}/include/lldb/API/SBError.h"\
+" ${SRCROOT}/include/lldb/API/SBEvent.h"\
+" ${SRCROOT}/include/lldb/API/SBFrame.h"\
+" ${SRCROOT}/include/lldb/API/SBFunction.h"\
+" ${SRCROOT}/include/lldb/API/SBLineEntry.h"\
+" ${SRCROOT}/include/lldb/API/SBListener.h"\
+" ${SRCROOT}/include/lldb/API/SBModule.h"\
+" ${SRCROOT}/include/lldb/API/SBProcess.h"\
+" ${SRCROOT}/include/lldb/API/SBSourceManager.h"\
+" ${SRCROOT}/include/lldb/API/SBStringList.h"\
+" ${SRCROOT}/include/lldb/API/SBSymbol.h"\
+" ${SRCROOT}/include/lldb/API/SBSymbolContext.h"\
+" ${SRCROOT}/include/lldb/API/SBTarget.h"\
+" ${SRCROOT}/include/lldb/API/SBThread.h"\
+" ${SRCROOT}/include/lldb/API/SBType.h"\
+" ${SRCROOT}/include/lldb/API/SBValue.h"
+
+
+if [ $Debug == 1 ]
+then
+ echo "Header files are:"
+ echo ${HEADER_FILES}
+fi
+
+NeedToUpdate=0
+
+swig_output_file=${SCRIPT_INPUT_FILE_1}
+
+if [ ! -f $swig_output_file ]
+then
+ NeedToUpdate=1
+ if [ $Debug == 1 ]
+ then
+ echo "Failed to find LLDBWrapPython.cpp"
+ fi
+fi
+
+if [ $NeedToUpdate == 0 ]
+then
+ for hdrfile in ${HEADER_FILES}
+ do
+ if [ $hdrfile -nt $swig_output_file ]
+ then
+ NeedToUpdate=1
+ if [ $Debug == 1 ]
+ then
+ echo "${hdrfile} is newer than ${swig_output_file}"
+ echo "swig file will need to be re-built."
+ fi
+ fi
+ done
+fi
+
+framework_python_dir="${CONFIGURATION_BUILD_DIR}/LLDB.framework/Versions/A/Resources/Python"
+
+if [ ! -L "${framework_python_dir}/_lldb.so" ]
+then
+ NeedToUpdate=1
+fi
+
+if [ ! -f "${framework_python_dir}/lldb.py" ]
+then
+ NeedToUpdate=1
+fi
+
+
+if [ $NeedToUpdate == 0 ]
+then
+ echo "Everything is up-to-date."
+ exit 0
+else
+ echo "SWIG needs to be re-run."
+fi
+
+
+# Build the SWIG C++ wrapper file for Python.
+
+swig -c++ -shadow -python -I"${SRCROOT}/include" -I./. -outdir "${CONFIGURATION_BUILD_DIR}" -o "${SCRIPT_INPUT_FILE_1}" "${SCRIPT_INPUT_FILE_0}"
+
+# Edit the C++ wrapper file that SWIG generated for Python. There are two
+# global string replacements needed, which the following script file takes
+# care of. It reads in 'LLDBWrapPython.cpp' and generates
+# 'LLDBWrapPython.cpp.edited'.
+
+# The need for this has been eliminated by fixing the namespace qualifiers on return types.
+# Leaving this here for now, just in case...
+#
+#if [ -f "${SRCROOT}/scripts/Python/edit-swig-python-wrapper-file.py" ]
+#then
+# python "${SRCROOT}/scripts/Python/edit-swig-python-wrapper-file.py"
+#fi
+
+#
+# Now that we've got a C++ file we're happy with (hopefully), rename the
+# edited file and move it to the appropriate places.
+#
+
+if [ -f "${SCRIPT_INPUT_FILE_1}.edited" ]
+then
+ mv "${SCRIPT_INPUT_FILE_1}.edited" "${SCRIPT_INPUT_FILE_1}"
+fi
diff --git a/lldb/scripts/Python/edit-swig-python-wrapper-file.py b/lldb/scripts/Python/edit-swig-python-wrapper-file.py
new file mode 100644
index 00000000000..a8c43239471
--- /dev/null
+++ b/lldb/scripts/Python/edit-swig-python-wrapper-file.py
@@ -0,0 +1,58 @@
+#
+# edit-swig-python-wrapper-file.py
+#
+# This script performs some post-processing editing on the C++ file that
+# SWIG generates for python, after running on 'lldb.swig'. In
+# particular, the types SWIGTYPE_p_SBThread and SWIGTYPE_p_SBTarget are
+# being used, when the types that *should* be used are
+# SWIGTYPE_p_lldb__SBThread and SWIGTYPE_p_lldb__SBTarget.
+# This script goes through the C++ file SWIG generated, reading it in line
+# by line and doing a search-and-replace for these strings.
+#
+
+
+import os
+
+full_input_name = os.environ["SCRIPT_INPUT_FILE_1"];
+full_output_name = full_input_name + ".edited"
+
+try:
+ f_in = open (full_input_name, 'r')
+except IOError:
+ print "Error: Unable to open file for reading: " + full_input_name
+else:
+ try:
+ f_out = open (full_output_name, 'w')
+ except IOError:
+ print "Error: Unable to open file for writing: " + full_output_name
+ else:
+ target_typedef_found = False
+ thread_typedef_found = False
+
+ try:
+ line = f_in.readline()
+ except IOError:
+ print "Error occurred while reading file."
+ else:
+ while line:
+ #
+ #
+ if (line.find ("SWIGTYPE_p_SBTarget")):
+ if (line.find ("define") < 0):
+ line = line.replace ("SWIGTYPE_p_SBTarget",
+ "SWIGTYPE_p_lldb__SBTarget")
+ if (line.find ("SWIGTYPE_p_SBThread")):
+ if (line.find ("define") < 0):
+ line = line.replace ("SWIGTYPE_p_SBThread",
+ "SWIGTYPE_p_lldb__SBThread")
+ f_out.write (line)
+ try:
+ line = f_in.readline()
+ except IOError:
+ print "Error occurred while reading file."
+
+ try:
+ f_in.close()
+ f_out.close()
+ except:
+ print "Error occurred while closing files"
diff --git a/lldb/scripts/Python/finish-swig-Python-LLDB.sh b/lldb/scripts/Python/finish-swig-Python-LLDB.sh
new file mode 100755
index 00000000000..293a8b18c66
--- /dev/null
+++ b/lldb/scripts/Python/finish-swig-Python-LLDB.sh
@@ -0,0 +1,45 @@
+#! /bin/sh
+
+# finish-swig-Python.sh
+#
+# For the Python script interpreter (external to liblldb) to be able to import
+# and use the lldb module, there must be a "_lldb.so" in the framework
+# resources directory. Here we make a symlink called "_lldb.so" that just
+# points to the executable in the LLDB.framework and copy over the needed
+# .py files.
+
+if [ ! -d "${TARGET_BUILD_DIR}/LLDB.framework" ]
+then
+ echo "Error: Unable to find LLDB.framework" >&2
+ exit 1
+fi
+
+# Make the Python directory down in the framework if it doesn't already exist
+framework_python_dir="${TARGET_BUILD_DIR}/LLDB.framework/Versions/A/Resources/Python"
+if [ ! -d "${framework_python_dir}" ]
+then
+ mkdir -p "${framework_python_dir}"
+fi
+
+# Make the symlink that the script bridge for Python will need in the Python
+# framework directory
+if [ ! -L "${framework_python_dir}/_lldb.so" ]
+then
+ cd "${framework_python_dir}"
+ ln -s "../../LLDB" _lldb.so
+fi
+
+# Copy the python module (lldb.py) that was generated by SWIG
+# over to the framework Python directory
+if [ -f "${CONFIGURATION_BUILD_DIR}/lldb.py" ]
+then
+ cp "${CONFIGURATION_BUILD_DIR}/lldb.py" "${framework_python_dir}"
+fi
+
+# Copy the embedded interpreter script over to the framework Python directory
+if [ -f "${SRCROOT}/source/Interpreter/embedded_interpreter.py" ]
+then
+ cp "${SRCROOT}/source/Interpreter/embedded_interpreter.py" "${framework_python_dir}"
+fi
+
+exit 0
diff --git a/lldb/scripts/build-llvm.pl b/lldb/scripts/build-llvm.pl
new file mode 100644
index 00000000000..3adfc11996f
--- /dev/null
+++ b/lldb/scripts/build-llvm.pl
@@ -0,0 +1,409 @@
+#!/usr/bin/perl
+
+# This script will take a number ($ENV{SCRIPT_INPUT_FILE_COUNT}) of static archive files
+# and pull them apart into object files. These object files will be placed in a directory
+# named the same as the archive itself without the extension. Each object file will then
+# get renamed to start with the archive name and a '-' character (for archive.a(object.o)
+# the object file would becomde archive-object.o. Then all object files are re-made into
+# a single static library. This can help avoid name collisions when different archive
+# files might contain object files with the same name.
+
+use strict;
+use File::Basename;
+use File::Glob ':glob';
+use List::Util qw[min max];
+
+our $llvm_dstroot = $ENV{SCRIPT_INPUT_FILE_0};
+
+our $libedis_outfile = $ENV{SCRIPT_OUTPUT_FILE_0};
+our ($libedis_basename, $libedis_dirname) = fileparse ($libedis_outfile);
+our @libedis_slices; # Skinny mach-o slices for libEnhancedDisassembly.dylib
+
+our $llvm_clang_outfile = $ENV{SCRIPT_OUTPUT_FILE_1};
+our ($llvm_clang_basename, $llvm_clang_dirname) = fileparse ($llvm_clang_outfile);
+our @llvm_clang_slices; # paths to the single architecture static libraries (archives)
+
+our $llvm_configuration = $ENV{LLVM_CONFIGURATION};
+
+our $llvm_revision = "'{2010-06-01T13:00}'";
+our $llvm_source_dir = "$ENV{SRCROOT}";
+our $cc = "$ENV{DEVELOPER_BIN_DIR}/gcc-4.2";
+our $cxx = "$ENV{DEVELOPER_BIN_DIR}/g++-4.2";
+our @archs = split (/\s+/, $ENV{ARCHS});
+
+our @archive_files = (
+ "$llvm_configuration/lib/libplugin_llvmc_Base.a",
+ "$llvm_configuration/lib/libplugin_llvmc_Clang.a",
+ "$llvm_configuration/lib/libclangAnalysis.a",
+ "$llvm_configuration/lib/libclangAST.a",
+ "$llvm_configuration/lib/libclangBasic.a",
+ "$llvm_configuration/lib/libclangCodeGen.a",
+ "$llvm_configuration/lib/libclangFrontend.a",
+ "$llvm_configuration/lib/libclangDriver.a",
+ "$llvm_configuration/lib/libclangIndex.a",
+ "$llvm_configuration/lib/libclangLex.a",
+ "$llvm_configuration/lib/libclangRewrite.a",
+ "$llvm_configuration/lib/libclangParse.a",
+ "$llvm_configuration/lib/libclangSema.a",
+ "$llvm_configuration/lib/libCompilerDriver.a",
+ "$llvm_configuration/lib/libEnhancedDisassembly.a",
+ "$llvm_configuration/lib/libLLVMAnalysis.a",
+ "$llvm_configuration/lib/libLLVMArchive.a",
+ "$llvm_configuration/lib/libLLVMARMAsmParser.a",
+ "$llvm_configuration/lib/libLLVMARMAsmPrinter.a",
+ "$llvm_configuration/lib/libLLVMARMCodeGen.a",
+ "$llvm_configuration/lib/libLLVMARMDisassembler.a",
+ "$llvm_configuration/lib/libLLVMARMInfo.a",
+ "$llvm_configuration/lib/libLLVMAsmParser.a",
+ "$llvm_configuration/lib/libLLVMAsmPrinter.a",
+ "$llvm_configuration/lib/libLLVMBitReader.a",
+ "$llvm_configuration/lib/libLLVMBitWriter.a",
+ "$llvm_configuration/lib/libLLVMCodeGen.a",
+ "$llvm_configuration/lib/libLLVMCore.a",
+ "$llvm_configuration/lib/libLLVMExecutionEngine.a",
+ "$llvm_configuration/lib/libLLVMInstCombine.a",
+ "$llvm_configuration/lib/libLLVMInstrumentation.a",
+ "$llvm_configuration/lib/libLLVMipa.a",
+ "$llvm_configuration/lib/libLLVMInterpreter.a",
+ "$llvm_configuration/lib/libLLVMipo.a",
+ "$llvm_configuration/lib/libLLVMJIT.a",
+ "$llvm_configuration/lib/libLLVMLinker.a",
+ "$llvm_configuration/lib/libLLVMMC.a",
+ "$llvm_configuration/lib/libLLVMMCParser.a",
+ "$llvm_configuration/lib/libLLVMScalarOpts.a",
+ "$llvm_configuration/lib/libLLVMSelectionDAG.a",
+ "$llvm_configuration/lib/libLLVMSupport.a",
+ "$llvm_configuration/lib/libLLVMSystem.a",
+ "$llvm_configuration/lib/libLLVMTarget.a",
+ "$llvm_configuration/lib/libLLVMTransformUtils.a",
+ "$llvm_configuration/lib/libLLVMX86AsmParser.a",
+ "$llvm_configuration/lib/libLLVMX86AsmPrinter.a",
+ "$llvm_configuration/lib/libLLVMX86CodeGen.a",
+ "$llvm_configuration/lib/libLLVMX86Disassembler.a",
+ "$llvm_configuration/lib/libLLVMX86Info.a",
+ "$llvm_configuration/lib/libclangChecker.a"
+);
+
+if (-l $llvm_dstroot)
+{
+ print "Using standard LLVM build directory...\n";
+ # LLVM in the "lldb" root is a symlink which indicates we are using a
+ # standard LLVM build directory where everything is built into the
+ # same folder
+ create_single_llvm_arhive_for_arch ($llvm_dstroot, 0);
+ my $llvm_dstroot_archive = "$llvm_dstroot/$llvm_clang_basename";
+ push @llvm_clang_slices, $llvm_dstroot_archive;
+ create_dstroot_file ($llvm_clang_basename, $llvm_clang_dirname, \@llvm_clang_slices, $llvm_clang_basename);
+ my $llvm_dstroot_edis = "$llvm_dstroot/$llvm_configuration/lib/libEnhancedDisassembly.dylib";
+ if (-f $llvm_dstroot_edis)
+ {
+ push @libedis_slices, $llvm_dstroot_edis;
+ create_dstroot_file ($libedis_basename, $libedis_dirname, \@libedis_slices, $libedis_basename);
+ }
+ exit 0;
+}
+
+
+if ($ENV{CONFIGURATION} eq "Debug" or $ENV{CONFIGURATION} eq "Release")
+{
+ # Check for an old llvm source install (not the minimal zip based
+ # install by looking for a .svn file in the llvm directory
+ chomp(my $llvm_zip_md5 = `md5 -q $ENV{SRCROOT}/llvm.zip`);
+ my $llvm_zip_md5_file = "$ENV{SRCROOT}/llvm/$llvm_zip_md5";
+ if (!-e "$llvm_zip_md5_file")
+ {
+ print "Updating LLVM to use checkpoint from: '$ENV{SRCROOT}/llvm.zip'...\n";
+ if (-d "$ENV{SRCROOT}/llvm")
+ {
+ do_command ("cd '$ENV{SRCROOT}' && rm -rf llvm", "removing old llvm repository", 1);
+ }
+ do_command ("cd '$ENV{SRCROOT}' && unzip -q llvm.zip && touch '$llvm_zip_md5_file'", "expanding llvm.zip", 1);
+ }
+
+ # We use the stuff in "lldb/llvm" for non B&I builds
+ if (!-e $libedis_outfile)
+ {
+ print "Copying '$ENV{SRCROOT}/llvm/$libedis_basename' to '$libedis_outfile'...\n";
+ do_command ("cp '$ENV{SRCROOT}/llvm/$libedis_basename' '$libedis_outfile'", "copying libedis", 1);
+ }
+ exit 0;
+}
+
+# If our output file already exists then we need not generate it again.
+if (-e $llvm_clang_outfile and -e $libedis_outfile)
+{
+ exit 0;
+}
+
+
+# Get our options
+
+our $debug = 1;
+
+sub parallel_guess
+{
+ my $cpus = `sysctl -n hw.availcpu`;
+ chomp ($cpus);
+ my $memsize = `sysctl -n hw.memsize`;
+ chomp ($memsize);
+ my $max_cpus_by_memory = int($memsize / (750 * 1024 * 1024));
+ return min($max_cpus_by_memory, $cpus);
+}
+sub build_llvm
+{
+ #my $extra_svn_options = $debug ? "" : "--quiet";
+ my $svn_options = "--quiet --revision $llvm_revision";
+ if (-d "$llvm_source_dir/llvm")
+ {
+ print "Using existing llvm sources in: '$llvm_source_dir/llvm'\n";
+ # print "Updating llvm to revision $llvm_revision\n";
+ # do_command ("cd '$llvm_source_dir/llvm' && svn update $svn_options", "updating llvm from repository", 1);
+ # print "Updating clang to revision $llvm_revision\n";
+ # do_command ("cd '$llvm_source_dir/llvm/tools/clang' && svn update $svn_options", "updating clang from repository", 1);
+ }
+ else
+ {
+ print "Checking out llvm sources from revision $llvm_revision...\n";
+ do_command ("cd '$llvm_source_dir' && svn co $svn_options http://llvm.org/svn/llvm-project/llvm/trunk llvm", "checking out llvm from repository", 1);
+ print "Checking out clang sources from revision $llvm_revision...\n";
+ do_command ("cd '$llvm_source_dir/llvm/tools' && svn co $svn_options http://llvm.org/svn/llvm-project/cfe/trunk clang", "checking out clang from repository", 1);
+ print "Removing the llvm/test directory...\n";
+ do_command ("cd '$llvm_source_dir' && rm -rf llvm/test", "removing test directory", 1);
+ }
+
+ # Make the llvm build directory
+ my $arch_idx = 0;
+ foreach my $arch (@archs)
+ {
+ my $llvm_dstroot_arch = "${llvm_dstroot}/${arch}";
+
+ # if the arch destination root exists we have already built it
+ my $do_configure = 0;
+ my $do_make = 0;
+
+ my $llvm_dstroot_arch_archive = "$llvm_dstroot_arch/$llvm_clang_basename";
+ print "LLVM architecture root for ${arch} exists at '$llvm_dstroot_arch'...";
+ if (-e $llvm_dstroot_arch)
+ {
+ print "YES\n";
+ $do_configure = !-e "$llvm_dstroot_arch/config.log";
+
+ # dstroot for llvm build exists, make sure all .a files are built
+ for my $llvm_lib (@archive_files)
+ {
+ if (!-e "$llvm_dstroot_arch/$llvm_lib")
+ {
+ print "missing archive: '$llvm_dstroot_arch/$llvm_lib'\n";
+ $do_make = 1;
+ }
+ }
+ if (!-e $llvm_dstroot_arch_archive)
+ {
+ $do_make = 1;
+ }
+ }
+ else
+ {
+ print "NO\n";
+ do_command ("mkdir -p '$llvm_dstroot_arch'", "making llvm build directory '$llvm_dstroot_arch'", 1);
+ $do_configure = 1;
+ $do_make = 1;
+ }
+
+ # If this is the first architecture, then make a symbolic link
+ # for any header files that get generated.
+ if ($arch_idx == 0)
+ {
+ if (!-l "$llvm_dstroot/llvm")
+ {
+ do_command ("cd $llvm_dstroot && ln -s './${arch}' llvm");
+ }
+ }
+
+ if ($do_configure)
+ {
+ # Build llvm and clang
+ print "Configuring clang ($arch) in '$llvm_dstroot_arch'...\n";
+ my $lldb_configuration_options = '';
+ $llvm_configuration eq 'Release' and $lldb_configuration_options .= '--enable-optimized';
+ do_command ("cd '$llvm_dstroot_arch' && '$llvm_source_dir/llvm/configure' $lldb_configuration_options --enable-targets=x86,x86_64,arm --build=$arch-apple-darwin10 CC=\"$cc -arch $arch\" CXX=\"$cxx -arch $arch\"",
+ "configuring llvm build", 1);
+ }
+
+ if ($do_make)
+ {
+ # Build llvm and clang
+ my $num_cpus = parallel_guess();
+ print "Building clang using $num_cpus cpus ($arch)...\n";
+ do_command ("cd '$llvm_dstroot_arch' && make -j$num_cpus clang-only VERBOSE=1 PROJECT_NAME='llvm'", "making llvm and clang", 1);
+ do_command ("cd '$llvm_dstroot_arch' && make -j$num_cpus tools-only VERBOSE=1 PROJECT_NAME='llvm' EDIS_VERSION=1", "making libedis", 1);
+ # Combine all .o files from a bunch of static libraries from llvm
+ # and clang into a single .a file.
+ create_single_llvm_arhive_for_arch ($llvm_dstroot_arch, 1);
+ }
+
+ -f "$llvm_dstroot_arch_archive" and push @llvm_clang_slices, "$llvm_dstroot_arch_archive";
+ -f "$llvm_dstroot_arch/$llvm_configuration/lib/libEnhancedDisassembly.dylib" and push @libedis_slices, "$llvm_dstroot_arch/$llvm_configuration/lib/libEnhancedDisassembly.dylib";
+ ++$arch_idx;
+ }
+
+ # Combine all skinny slices of the LLVM/Clang combined archive
+ create_dstroot_file ($llvm_clang_basename, $llvm_clang_dirname, \@llvm_clang_slices, $llvm_clang_basename);
+
+ if (scalar(@libedis_slices))
+ {
+ # Combine all skinny slices of the libedis in SYMROOT
+ create_dstroot_file ($libedis_basename, $libedis_dirname, \@libedis_slices, $libedis_basename);
+
+ # Make dSYM for libedis in SYMROOT
+ do_command ("cd '$libedis_dirname' && dsymutil $libedis_basename", "making libedis dSYM", 1);
+
+ # strip debug symbols from libedis and copy into DSTROOT
+ -d "$ENV{DSTROOT}/Developer/usr/lib" or do_command ("mkdir -p '$ENV{DSTROOT}/Developer/usr/lib'", "Making directory '$ENV{DSTROOT}/Developer/usr/lib'", 1);
+ do_command ("cd '$libedis_dirname' && strip -Sx -o '$ENV{DSTROOT}/Developer/usr/lib/$libedis_basename' '$libedis_outfile'", "Stripping libedis and copying to DSTROOT", 1);
+ }
+}
+
+sub create_dstroot_file
+{
+ my $file = shift;
+ my $dir = shift;
+ my $fullpath = "$dir/$file"; # The path to the file to create
+ my $slice_aref = shift; # Array containing one or more skinny files that will be combined into $fullpath
+ my $what = shift; # Text describing the $fullpath
+
+ print "create_dstroot_file file = '$file', dir = '$dir', slices = (" . join (', ', @$slice_aref) . ") for what = '$what'\n";
+
+ if (-d $dir)
+ {
+ if (@$slice_aref > 0)
+ {
+ print "Creating and installing $what into '$fullpath'...\n";
+ my $lipo_command = "lipo -output '$fullpath' -create";
+ foreach (@$slice_aref) { $lipo_command .= " '$_'"; }
+ do_command ($lipo_command, "creating $what universal output file", 1);
+ }
+
+
+ if (!-e $fullpath)
+ {
+ # die "error: '$fullpath' is missing\n";
+ }
+ }
+ else
+ {
+ die "error: directory '$dir' doesn't exist to receive file '$file'\n";
+ }
+}
+#----------------------------------------------------------------------
+# quote the path if needed and realpath it if the -r option was
+# specified
+#----------------------------------------------------------------------
+sub finalize_path
+{
+ my $path = shift;
+ # Realpath all paths that don't start with "/"
+ $path =~ /^[^\/]/ and $path = abs_path($path);
+
+ # Quote the path if asked to, or if there are special shell characters
+ # in the path name
+ my $has_double_quotes = $path =~ /["]/;
+ my $has_single_quotes = $path =~ /[']/;
+ my $needs_quotes = $path =~ /[ \$\&\*'"]/;
+ if ($needs_quotes)
+ {
+ # escape and double quotes in the path
+ $has_double_quotes and $path =~ s/"/\\"/g;
+ $path = "\"$path\"";
+ }
+ return $path;
+}
+
+sub do_command
+{
+ my $cmd = shift;
+ my $description = @_ ? shift : "command";
+ my $die_on_fail = @_ ? shift : undef;
+ $debug and print "% $cmd\n";
+ system ($cmd);
+ if ($? == -1)
+ {
+ $debug and printf ("error: %s failed to execute: $!\n", $description);
+ $die_on_fail and $? and exit(1);
+ return $?;
+ }
+ elsif ($? & 127)
+ {
+ $debug and printf("error: %s child died with signal %d, %s coredump\n",
+ $description,
+ ($? & 127),
+ ($? & 128) ? 'with' : 'without');
+ $die_on_fail and $? and exit(1);
+ return $?;
+ }
+ else
+ {
+ my $exit = $? >> 8;
+ if ($exit)
+ {
+ $debug and printf("error: %s child exited with value %d\n", $description, $exit);
+ $die_on_fail and exit(1);
+ }
+ return $exit;
+ }
+}
+
+sub create_single_llvm_arhive_for_arch
+{
+ my $arch_dstroot = shift;
+ my $split_into_objects = shift;
+ my @object_dirs;
+ my $object_dir;
+ my $tmp_dir = $arch_dstroot;
+ my $arch_output_file = "$arch_dstroot/$llvm_clang_basename";
+ -e $arch_output_file and return;
+ my $files = "$arch_dstroot/files.txt";
+ open (FILES, ">$files") or die "Can't open $! for writing...\n";
+
+ for my $path (@archive_files)
+ {
+ my $archive_fullpath = finalize_path ("$arch_dstroot/$path");
+ if (-e $archive_fullpath)
+ {
+ if ($split_into_objects)
+ {
+ my ($archive_file, $archive_dir, $archive_ext) = fileparse($archive_fullpath, ('.a'));
+
+ $object_dir = "$tmp_dir/$archive_file";
+ push @object_dirs, $object_dir;
+
+ do_command ("cd '$tmp_dir'; mkdir '$archive_file'; cd '$archive_file'; ar -x $archive_fullpath");
+
+ my @objects = bsd_glob("$object_dir/*.o");
+
+ foreach my $object (@objects)
+ {
+ my ($o_file, $o_dir) = fileparse($object);
+ my $new_object = "$object_dir/${archive_file}-$o_file";
+ print FILES "$new_object\n";
+ do_command ("mv '$object' '$new_object'");
+ }
+ }
+ else
+ {
+ # just add the .a files into the file list
+ print FILES "$archive_fullpath\n";
+ }
+ }
+ }
+ close (FILES);
+ do_command ("libtool -static -o '$arch_output_file' -filelist '$files'");
+
+ foreach $object_dir (@object_dirs)
+ {
+ do_command ("rm -rf '$object_dir'");
+ }
+ do_command ("rm -rf '$files'");
+}
+
+build_llvm();
diff --git a/lldb/scripts/build-swig-wrapper-classes.sh b/lldb/scripts/build-swig-wrapper-classes.sh
new file mode 100755
index 00000000000..3d1cf74344f
--- /dev/null
+++ b/lldb/scripts/build-swig-wrapper-classes.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+
+# build-swig-wrapper-classes.sh
+#
+# For each scripting language liblldb supports, we need to create the
+# appropriate Script Bridge wrapper classes for that language so that
+# users can call Script Bridge functions from within the script interpreter.
+#
+# We use SWIG to help create the appropriate wrapper classes/functions for
+# the scripting language. In some cases the file generated by SWIG may
+# need some tweaking before it is completely ready to use.
+
+debug_flag=$1
+
+if [ -n "$debug_flag" -a "$debug_flag" == "-debug" ]
+then
+ Debug=1
+else
+ Debug=0
+fi
+
+#
+# Verify that 'lldb.swig' exists.
+#
+
+if [ ! -f ${SRCROOT}/scripts/lldb.swig ]
+then
+ echo Error: unable to find file 'lldb.swig' >&2
+ exit 1
+fi
+
+if [ $Debug == 1 ]
+then
+ echo "Found lldb.swig file"
+fi
+
+#
+# For each scripting language, make sure the build script for that language
+# exists, and if so, call it.
+#
+# For now the only language we support is Python, but we expect this to
+# change.
+
+languages="Python"
+cwd=${SRCROOT}/scripts
+
+for curlang in $languages
+do
+ if [ $Debug == 1 ]
+ then
+ echo "Current language is $curlang"
+ fi
+
+ if [ ! -d "$cwd/$curlang" ]
+ then
+ echo "Error: unable to find $curlang script sub-dirctory" >&2
+ continue
+ else
+
+ if [ $Debug == 1 ]
+ then
+ echo "Found $curlang sub-directory"
+ fi
+
+ cd $cwd/$curlang
+
+ filename="./build-swig-${curlang}.sh"
+
+ if [ ! -f $filename ]
+ then
+ echo "Error: unable to find swig build script for $curlang: $filename" >&2
+ continue
+ else
+
+ if [ $Debug == 1 ]
+ then
+ echo "Found $curlang build script."
+ echo "Executing $curlang build script..."
+ fi
+
+ ./build-swig-${curlang}.sh
+ fi
+ fi
+done
+
diff --git a/lldb/scripts/checkpoint-llvm.pl b/lldb/scripts/checkpoint-llvm.pl
new file mode 100755
index 00000000000..5c1293b0f33
--- /dev/null
+++ b/lldb/scripts/checkpoint-llvm.pl
@@ -0,0 +1,101 @@
+#!/usr/bin/perl
+
+# This script should be pointed to a valid llvm.build folder that
+# was created using the "build-llvm.pl" shell script. It will create
+# a new llvm.zip file that can be checked into the respository
+# at lldb/llvm.zip
+
+use strict;
+use Cwd 'abs_path';
+use File::Basename;
+use File::Temp qw/ tempfile tempdir /;
+our $debug = 1;
+
+
+sub do_command
+{
+ my $cmd = shift;
+ my $description = @_ ? shift : "command";
+ my $die_on_fail = @_ ? shift : undef;
+ $debug and print "% $cmd\n";
+ system ($cmd);
+ if ($? == -1)
+ {
+ $debug and printf ("error: %s failed to execute: $!\n", $description);
+ $die_on_fail and $? and exit(1);
+ return $?;
+ }
+ elsif ($? & 127)
+ {
+ $debug and printf("error: %s child died with signal %d, %s coredump\n",
+ $description,
+ ($? & 127),
+ ($? & 128) ? 'with' : 'without');
+ $die_on_fail and $? and exit(1);
+ return $?;
+ }
+ else
+ {
+ my $exit = $? >> 8;
+ if ($exit)
+ {
+ $debug and printf("error: %s child exited with value %d\n", $description, $exit);
+ $die_on_fail and exit(1);
+ }
+ return $exit;
+ }
+}
+
+if (@ARGV == 4)
+{
+ my $llvm_source_dir = abs_path(shift @ARGV); # The llvm source that contains full llvm and clang sources
+ my $llvm_build_dir = abs_path(shift @ARGV); # The llvm build directory that contains headers and
+ my $lldb_build_dir = abs_path(shift @ARGV); # the build directory that contains the fat libEnhancedDisassembly.dylib
+ my $llvm_zip_file = abs_path(shift @ARGV);
+
+ printf("LLVM sources : '%s'\n", $llvm_source_dir);
+ printf("LLVM build : '%s'\n", $llvm_build_dir);
+ printf("LLDB build : '%s'\n", $lldb_build_dir);
+ printf("LLVM zip file: '%s'\n", $llvm_zip_file);
+
+ -e $llvm_build_dir or die "LLVM build directory doesn't exist: '$llvm_build_dir': $!\n";
+ -l "$llvm_build_dir/llvm" || die "Couldn't find llvm symlink '$llvm_build_dir/llvm': $!\n";
+
+ my $temp_dir = tempdir( CLEANUP => 1 );
+ print "temp dir = '$temp_dir'\n";
+ my $llvm_checkpoint_dir = "$temp_dir/llvm";
+ mkdir "$llvm_checkpoint_dir" or die "Couldn't make 'llvm' in '$temp_dir'\n";
+
+ my @rsync_src_dst_paths =
+ (
+ "$llvm_source_dir/include", "$llvm_checkpoint_dir",
+ "$llvm_source_dir/tools/clang/include", "$llvm_checkpoint_dir/tools/clang",
+ "$llvm_build_dir/llvm/include", "$llvm_checkpoint_dir",
+ "$llvm_build_dir/llvm/tools/clang/include", "$llvm_checkpoint_dir/tools/clang",
+ );
+
+ while (@rsync_src_dst_paths)
+ {
+ my $rsync_src = shift @rsync_src_dst_paths;
+ my $rsync_dst = shift @rsync_src_dst_paths;
+ print "rsync_src = '$rsync_src'\n";
+ print "rsync_dst = '$rsync_dst'\n";
+ if (-e $rsync_src)
+ {
+ my ($rsync_dst_file, $rsync_dst_dir) = fileparse ($rsync_dst);
+ print "rsync_dst_dir = '$rsync_dst_dir'\n";
+ -e $rsync_dst_dir or do_command ("mkdir -p '$rsync_dst_dir'");
+ do_command ("rsync -amvC --exclude='*.tmp' --exclude='*.txt' --exclude='*.TXT' --exclude='*.td' --exclude='\.dir' --exclude=Makefile '$rsync_src' '$rsync_dst'");
+ }
+ }
+
+ do_command ("cp '$llvm_build_dir/libllvmclang.a' '$llvm_checkpoint_dir'", "Copying libllvmclang.a", 1);
+ do_command ("cp '$lldb_build_dir/libEnhancedDisassembly.dylib' '$llvm_checkpoint_dir'", "Copying libEnhancedDisassembly.dylib", 1);
+ do_command ("rm -rf '$llvm_zip_file'", "Removing old llvm checkpoint file '$llvm_zip_file'", 1);
+ do_command ("(cd '$temp_dir' ; zip -r '$llvm_zip_file' 'llvm')", "Zipping llvm checkpoint directory '$llvm_checkpoint_dir' to '$llvm_zip_file'", 1);
+}
+else
+{
+ print "USAGE\n\tcheckpoint-llvm.pl <llvm-sources> <llvm-build> <lldb-build> <llvm-zip>\n\n";
+ print "EXAMPLE\n\tcd lldb\n\t./scripts/checkpoint-llvm.pl llvm build/lldb.build/BuildAndIntegration/LLDB.build/DerivedSources/llvm.build build/BuildAndIntegration llvm.zip\n";
+}
diff --git a/lldb/scripts/finish-swig-wrapper-classes.sh b/lldb/scripts/finish-swig-wrapper-classes.sh
new file mode 100755
index 00000000000..5d9713d06a2
--- /dev/null
+++ b/lldb/scripts/finish-swig-wrapper-classes.sh
@@ -0,0 +1,71 @@
+#! /bin/sh
+
+# finish-swig-wrapper-classes.sh
+#
+# For each scripting language liblldb supports, we need to create the
+# appropriate Script Bridge wrapper classes for that language so that
+# users can call Script Bridge functions from within the script interpreter.
+#
+# We use SWIG to create a C++ file containing the appropriate wrapper classes
+# and funcitons for each scripting language, before liblldb is built (thus
+# the C++ file can be compiled into liblldb. In some cases, additional work
+# may need to be done after liblldb has been compiled, to make the scripting
+# language stuff fully functional. Any such post-processing is handled through
+# the shell scripts called here.
+
+debug_flag=$1
+
+if [ -n "$debug_flag" -a "$debug_flag" == "-debug" ]
+then
+ Debug=1
+else
+ Debug=0
+fi
+
+
+#
+# For each scripting language, see if a post-processing script for that
+# language exists, and if so, call it.
+#
+# For now the only language we support is Python, but we expect this to
+# change.
+
+languages="Python"
+cwd=${SRCROOT}/scripts
+
+for curlang in $languages
+do
+ if [ $Debug == 1 ]
+ then
+ echo "Current language is $curlang"
+ fi
+
+ if [ ! -d "$cwd/$curlang" ]
+ then
+ echo "error: unable to find $curlang script sub-dirctory" >&2
+ continue
+ else
+
+ if [ $Debug == 1 ]
+ then
+ echo "Found $curlang sub-directory"
+ fi
+
+ cd $cwd/$curlang
+
+ filename="./finish-swig-${curlang}-${TARGET_NAME}.sh"
+
+ if [ -f $filename ]
+ then
+ if [ $Debug == 1 ]
+ then
+ echo "Found $curlang post-processing script for ${TARGET_NAME}"
+ echo "Executing $curlang post-processing script..."
+ fi
+
+ ./finish-swig-${curlang}-${TARGET_NAME}.sh
+ fi
+ fi
+done
+
+exit 0
diff --git a/lldb/scripts/install-lldb.sh b/lldb/scripts/install-lldb.sh
new file mode 100755
index 00000000000..0ba4e7c5ee2
--- /dev/null
+++ b/lldb/scripts/install-lldb.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+
+# This script will install the files from a "Debug" or "Release" build
+# directory into the developer folder specified.
+
+NUM_EXPECTED_ARGS=2
+
+PROGRAM=`basename $0`
+
+if [ $# -ne $NUM_EXPECTED_ARGS ]; then
+ echo This script will install the files from a 'Debug' or 'Release' build directory into the developer folder specified.
+ echo "usage: $PROGRAM <BUILD_DIR> <DEVELOPER_DIR>";
+ echo "example: $PROGRAM ./Debug /Developer"
+ echo "example: $PROGRAM /build/Release /Xcode4"
+ exit 1;
+fi
+
+BUILD_DIR=$1
+DEVELOPER_DIR=$2
+
+if [ -d $BUILD_DIR ]; then
+ if [ -d $DEVELOPER_DIR ]; then
+ if [ -e "$BUILD_DIR/debugserver" ]; then
+ echo Updating "$DEVELOPER_DIR/usr/bin/debugserver"
+ sudo rm -rf "$DEVELOPER_DIR/usr/bin/debugserver"
+ sudo cp "$BUILD_DIR/debugserver" "$DEVELOPER_DIR/usr/bin/debugserver"
+ fi
+
+ if [ -e "$BUILD_DIR/lldb" ]; then
+ echo Updating "$DEVELOPER_DIR/usr/bin/lldb"
+ sudo rm -rf "$DEVELOPER_DIR/usr/bin/lldb"
+ sudo cp "$BUILD_DIR/lldb" "$DEVELOPER_DIR/usr/bin/lldb"
+ fi
+
+ if [ -e "$BUILD_DIR/libEnhancedDisassembly.dylib" ]; then
+ echo Updating "$DEVELOPER_DIR/usr/lib/libEnhancedDisassembly.dylib"
+ sudo rm -rf "$DEVELOPER_DIR/usr/lib/libEnhancedDisassembly.dylib"
+ sudo cp "$BUILD_DIR/libEnhancedDisassembly.dylib" "$DEVELOPER_DIR/usr/lib/libEnhancedDisassembly.dylib"
+ fi
+
+ if [ -d "$BUILD_DIR/LLDB.framework" ]; then
+ echo Updating "$DEVELOPER_DIR/Library/PrivateFrameworks/LLDB.framework"
+ sudo rm -rf "$DEVELOPER_DIR/Library/PrivateFrameworks/LLDB.framework"
+ sudo cp -r "$BUILD_DIR/LLDB.framework" "$DEVELOPER_DIR/Library/PrivateFrameworks/LLDB.framework"
+ elif [ -e "$BUILD_DIR/LLDB.framework" ]; then
+ echo BUILD_DIR path to LLDB.framework is not a directory: "$BUILD_DIR/LLDB.framework"
+ exit 2;
+ fi
+
+ else
+ echo DEVELOPER_DIR must be a directory: "$DEVELOPER_DIR"
+ exit 3;
+ fi
+
+else
+ echo BUILD_DIR must be a directory: "$BUILD_DIR"
+ exit 4;
+fi
diff --git a/lldb/scripts/lldb.swig b/lldb/scripts/lldb.swig
new file mode 100644
index 00000000000..d9fd05b8488
--- /dev/null
+++ b/lldb/scripts/lldb.swig
@@ -0,0 +1,149 @@
+/*
+ lldb.swig
+
+ Created by Caroline Tice 1/18/2010
+
+ This is the input file for SWIG, to create the appropriate C++ wrappers and
+ functions for various scripting languages, to enable them to call the
+ liblldb Script Bridge functions.
+
+*/
+
+/* The name of the module to be created. */
+
+%module lldb
+
+%typemap(in) lldb::ReturnStatus {
+ $1 = (int) $input;
+}
+
+%typemap(freearg) lldb::ReturnStatus {
+}
+
+%typemap(out) lldb::ReturnStatus {
+ $result = SWIG_From_unsigned_SS_int(static_cast< unsigned int >($1));
+}
+
+/* Typemap definitions, to allow SWIG to properly handle 'char**' data types. */
+
+%typemap(in) char ** {
+ /* Check if is a list */
+ if (PyList_Check($input)) {
+ int size = PyList_Size($input);
+ int i = 0;
+ $1 = (char **) malloc((size+1) * sizeof(char));
+ for (i = 0; i < size; i++) {
+ PyObject *o = PyList_GetItem($input,i);
+ if (PyString_Check(o))
+ $1[i] = PyString_AsString(PyList_GetItem($input,i));
+ else {
+ PyErr_SetString(PyExc_TypeError,"list must contain strings");
+ free($1);
+ return NULL;
+ }
+ }
+ $1[i] = 0;
+ } else {
+ PyErr_SetString(PyExc_TypeError,"not a list");
+ return NULL;
+ }
+}
+
+%typemap(freearg) char** {
+ free((char *) $1);
+}
+
+%typemap(out) char** {
+ int len;
+ int i;
+ len = 0;
+ while ($1[len]) len++;
+ $result = PyList_New(len);
+ for (i = 0; i < len; i++) {
+ PyList_SetItem($result, i, PyString_FromString($1[i]));
+ }
+}
+
+
+/* The liblld header files to be included. */
+
+%{
+#include "lldb/lldb-types.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/SBCommandContext.h"
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBCompileUnit.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/API/SBFunction.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/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"
+using namespace lldb;
+using namespace lldb_private;
+%}
+
+/* Various liblldb typedefs that SWIG needs to know about. */
+
+%{
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef int int32_t;
+typedef int32_t pid_t;
+typedef uint32_t tid_t;
+typedef uint64_t addr_t;
+%}
+
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef int int32_t;
+typedef int32_t pid_t;
+typedef uint32_t tid_t;
+typedef uint64_t addr_t;
+
+
+%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/SBCommandContext.h"
+%include "lldb/API/SBCommandInterpreter.h"
+%include "lldb/API/SBCommandReturnObject.h"
+%include "lldb/API/SBCompileUnit.h"
+%include "lldb/API/SBDebugger.h"
+%include "lldb/API/SBError.h"
+%include "lldb/API/SBEvent.h"
+%include "lldb/API/SBFrame.h"
+%include "lldb/API/SBFunction.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/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/lldb-types.h"
+
+
diff --git a/lldb/scripts/sed-sources b/lldb/scripts/sed-sources
new file mode 100755
index 00000000000..f678ee27551
--- /dev/null
+++ b/lldb/scripts/sed-sources
@@ -0,0 +1,252 @@
+#!/usr/bin/perl
+
+use strict;
+use File::Find;
+use File::Temp qw/ tempfile tempdir /;
+use Getopt::Std;
+use Pod::Usage;
+use Text::Tabs;
+
+=head1 NAME
+
+B<sed-sources> -- Performs multiple sed commands on files with the ability to expand or unexpand tabs.
+
+=head1 SYNOPSIS
+
+B<sed-sources> [options] [file dir ...]
+
+=head1 DESCRIPTION
+
+Performs multiple sed commands (modify builtin %seds hash) on source files
+or any sources in directories. If no arguments are given, STDIN will be used
+as the source. If source files or directories are specified as arguments,
+all files will be transformed and overwritten with new versions. Use the B<-p>
+option to preview changes to STDOUT, or use the B<-b> option to make a backup
+or the original files.
+
+=head1 OPTIONS
+
+=over
+
+=item B<-b>
+
+Backup original source file by appending ".bak" before overwriting with the
+newly transformed file.
+
+=item B<-g>
+
+Display verbose debug logging.
+
+=item B<-e>
+
+Expand tabs to spaces (in addition to doing sed substitutions).
+
+=item B<-u>
+
+Unexpand spaces to tabs (in addition to doing sed substitutions).
+
+=item B<-p>
+
+Preview changes to STDOUT without modifying original source files.
+
+=item B<-r>
+
+Skip variants when doing multiple files (no _profile or _debug variants).
+
+=item B<-t N>
+
+Set the number of spaces per tab (default is 4) to use when expanding or
+unexpanding.
+
+=back
+
+=head1 EXAMPLES
+
+# Recursively process all source files in the current working directory
+# and and subdirectories and also expand tabs to spaces. All source files
+# will be overwritten with the newly transformed source files.
+
+% sed-sources -e $cwd
+
+# Recursively process all source files in the current working directory
+# and and subdirectories and also unexpand spaces to tabs and preview the
+# results to STDOUT
+
+% sed-sources -p -u $cwd
+
+# Same as above except use 8 spaces per tab.
+
+% sed-sources -p -u -t8 $cwd
+
+=cut
+
+
+our $opt_b = 0; # Backup original file?
+our $opt_g = 0; # Verbose debug output?
+our $opt_e = 0; # Expand tabs to spaces?
+our $opt_h = 0; # Show help?
+our $opt_m = 0; # Show help manpage style?
+our $opt_p = 0; # Preview changes to STDOUT?
+our $opt_t = 4; # Number of spaces per tab?
+our $opt_u = 0; # Unexpand spaces to tabs?
+getopts('eghmpt:u');
+
+$opt_m and show_manpage();
+$opt_h and help();
+
+our %seds = (
+ '\s+$' => "\n", # Get rid of spaces at the end of a line
+ '^\s+$' => "\n", # Get rid spaces on lines that are all spaces
+ '^\s*//\s*[Cc]opyright.*$' => '//', # Get rid of all copyright lines
+);
+
+
+sub show_manpage { exit pod2usage( verbose => 2 ); };
+sub help { exit pod2usage( verbose => 3, noperldoc => 1 ); };
+
+
+#----------------------------------------------------------------------
+# process_opened_file_handle
+#----------------------------------------------------------------------
+sub process_opened_file_handle
+{
+ my $in_fh = shift;
+ my $out_fh = shift;
+
+ # Set the number of spaces per tab for expand/unexpand
+ $tabstop = $opt_t;
+
+ while (my $line = <$in_fh>)
+ {
+ foreach my $key (keys %seds)
+ {
+ my $value = $seds{"$key"};
+ $line =~ s/$key/$value/g;
+ }
+ if ($opt_e) {
+ print $out_fh expand $line;
+ } elsif ($opt_u) {
+ print $out_fh unexpand $line;
+ } else {
+ print $out_fh $line;
+ }
+ }
+}
+
+#----------------------------------------------------------------------
+# process_file
+#----------------------------------------------------------------------
+sub process_file
+{
+ my $in_path = shift;
+ if (-T $in_path)
+ {
+ my $out_fh;
+ my $out_path;
+ if ($opt_p)
+ {
+ # Preview to STDOUT
+ $out_fh = *STDOUT;
+ print "#---------------------------------------------------------------------- \n";
+ print "# BEGIN: '$in_path'\n";
+ print "#---------------------------------------------------------------------- \n";
+ }
+ else
+ {
+ ($out_fh, $out_path) = tempfile();
+ $opt_g and print "temporary for '$in_path' is '$out_path'\n";
+ }
+ open (IN, "<$in_path") or die "error: can't open '$in_path' for reading: $!";
+ process_opened_file_handle (*IN, $out_fh);
+
+
+ # Close our input file
+ close (IN);
+
+ if ($opt_p)
+ {
+ print "#---------------------------------------------------------------------- \n";
+ print "# END: '$in_path'\n";
+ print "#---------------------------------------------------------------------- \n";
+ print "\n\n";
+ }
+ else
+ {
+ # Close the output file if it wasn't STDOUT
+ close ($out_fh);
+
+ # Backup file if requested
+ if ($opt_b)
+ {
+ my $backup_command = "cp '$in_path' '$in_path.bak'";
+ $opt_g and print "\% $backup_command\n";
+ system ($backup_command);
+ }
+
+ # Copy temp file over original
+ my $copy_command = "cp '$out_path' '$in_path'";
+ $opt_g and print "\% $copy_command\n";
+ system ($copy_command);
+ }
+ }
+}
+
+our @valid_extensions = ( "h", "cpp", "c", "m", "mm" );
+
+#----------------------------------------------------------------------
+# find_callback
+#----------------------------------------------------------------------
+sub find_callback
+{
+ my $file = $_;
+ my $fullpath = $File::Find::name;
+
+ foreach my $ext (@valid_extensions)
+ {
+ my $ext_regex = "\\.$ext\$";
+ if ($fullpath =~ /$ext_regex/i)
+ {
+ print "processing: '$fullpath'\n";
+ process_file ($fullpath);
+ return;
+ }
+ }
+ print " ignoring: '$fullpath'\n";
+}
+
+
+#----------------------------------------------------------------------
+# main
+#----------------------------------------------------------------------
+sub main
+{
+ if (@ARGV == 0)
+ {
+ # no args, take from STDIN and put to STDOUT
+ process_opened_file_handle (*STDIN, *STDOUT);
+ }
+ else
+ {
+ # Got args, any files we run into parse them, any directories
+ # we run into, search them for files
+ my $path;
+ foreach $path (@ARGV)
+ {
+ if (-f $path)
+ {
+ print "processing: '$path'\n";
+ process_file ($path);
+ }
+ else
+ {
+ print " searching: '$path'\n";
+ find(\&find_callback, $path);
+ }
+ }
+ }
+}
+
+
+
+# call the main function
+main(); \ No newline at end of file
diff --git a/lldb/source/API/SBAddress.cpp b/lldb/source/API/SBAddress.cpp
new file mode 100644
index 00000000000..482ecec1ce6
--- /dev/null
+++ b/lldb/source/API/SBAddress.cpp
@@ -0,0 +1,118 @@
+//===-- 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/Core/Address.h"
+
+using namespace lldb;
+
+
+SBAddress::SBAddress () :
+ m_lldb_object_ap ()
+{
+}
+
+SBAddress::SBAddress (const lldb_private::Address *lldb_object_ptr) :
+ m_lldb_object_ap ()
+{
+ if (lldb_object_ptr)
+ m_lldb_object_ap.reset (new lldb_private::Address(*lldb_object_ptr));
+}
+
+SBAddress::SBAddress (const SBAddress &rhs) :
+ m_lldb_object_ap ()
+{
+ if (rhs.IsValid())
+ m_lldb_object_ap.reset (new lldb_private::Address(*rhs.m_lldb_object_ap.get()));
+}
+
+SBAddress::~SBAddress ()
+{
+}
+
+const SBAddress &
+SBAddress::operator = (const SBAddress &rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ m_lldb_object_ap.reset (new lldb_private::Address(*rhs.m_lldb_object_ap.get()));
+ }
+ return *this;
+}
+
+bool
+SBAddress::IsValid () const
+{
+ return m_lldb_object_ap.get() != NULL && m_lldb_object_ap->IsValid();
+}
+
+void
+SBAddress::SetAddress (const lldb_private::Address *lldb_object_ptr)
+{
+ if (lldb_object_ptr)
+ {
+ if (m_lldb_object_ap.get())
+ *m_lldb_object_ap = *lldb_object_ptr;
+ else
+ m_lldb_object_ap.reset (new lldb_private::Address(*lldb_object_ptr));
+ return;
+ }
+ if (m_lldb_object_ap.get())
+ m_lldb_object_ap->Clear();
+}
+
+lldb::addr_t
+SBAddress::GetFileAddress () const
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->GetFileAddress();
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+lldb::addr_t
+SBAddress::GetLoadAddress (const SBProcess &process) const
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->GetLoadAddress(process.get());
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+SBAddress::OffsetAddress (addr_t offset)
+{
+ if (m_lldb_object_ap.get())
+ {
+ addr_t addr_offset = m_lldb_object_ap->GetOffset();
+ if (addr_offset != LLDB_INVALID_ADDRESS)
+ {
+ m_lldb_object_ap->SetOffset(addr_offset + offset);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+const lldb_private::Address *
+SBAddress::operator->() const
+{
+ return m_lldb_object_ap.get();
+}
+
+const lldb_private::Address &
+SBAddress::operator*() const
+{
+ return *m_lldb_object_ap;
+}
+
+
diff --git a/lldb/source/API/SBBlock.cpp b/lldb/source/API/SBBlock.cpp
new file mode 100644
index 00000000000..536febd99b7
--- /dev/null
+++ b/lldb/source/API/SBBlock.cpp
@@ -0,0 +1,47 @@
+//===-- 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/Symbol/Block.h"
+
+using namespace lldb;
+
+
+SBBlock::SBBlock () :
+ m_lldb_object_ptr (NULL)
+{
+}
+
+SBBlock::SBBlock (lldb_private::Block *lldb_object_ptr) :
+ m_lldb_object_ptr (lldb_object_ptr)
+{
+}
+
+SBBlock::~SBBlock ()
+{
+ m_lldb_object_ptr = NULL;
+}
+
+bool
+SBBlock::IsValid () const
+{
+ return m_lldb_object_ptr != NULL;
+}
+
+void
+SBBlock::AppendVariables (bool can_create, bool get_parent_variables, lldb_private::VariableList *var_list)
+{
+ if (IsValid())
+ {
+ m_lldb_object_ptr->AppendVariables (can_create, get_parent_variables, var_list);
+ }
+}
+
+
+
diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp
new file mode 100644
index 00000000000..2cf4e0b824f
--- /dev/null
+++ b/lldb/source/API/SBBreakpoint.cpp
@@ -0,0 +1,404 @@
+//===-- 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/SBProcess.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/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.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_break_sp ()
+{
+}
+
+SBBreakpoint::SBBreakpoint (const SBBreakpoint& rhs) :
+ m_break_sp (rhs.m_break_sp)
+{
+}
+
+
+SBBreakpoint::SBBreakpoint (const lldb::BreakpointSP &bp_sp) :
+ m_break_sp (bp_sp)
+{
+}
+
+SBBreakpoint::~SBBreakpoint()
+{
+}
+
+const SBBreakpoint &
+SBBreakpoint::operator = (const SBBreakpoint& rhs)
+{
+ if (this != &rhs)
+ {
+ m_break_sp = rhs.m_break_sp;
+ }
+ return *this;
+}
+
+break_id_t
+SBBreakpoint::GetID () const
+{
+ if (m_break_sp)
+ return m_break_sp->GetID();
+ return LLDB_INVALID_BREAK_ID;
+}
+
+
+bool
+SBBreakpoint::IsValid() const
+{
+ return m_break_sp;
+}
+
+void
+SBBreakpoint::Dump (FILE *f)
+{
+ if (m_break_sp)
+ {
+ if (f == NULL)
+ f = SBDebugger::GetOutputFileHandle();
+ if (f == NULL)
+ return;
+ lldb_private::StreamFile str (f);
+ m_break_sp->Dump (&str);
+ }
+}
+
+void
+SBBreakpoint::ClearAllBreakpointSites ()
+{
+ if (m_break_sp)
+ m_break_sp->ClearAllBreakpointSites ();
+}
+
+SBBreakpointLocation
+SBBreakpoint::FindLocationByAddress (addr_t vm_addr)
+{
+ SBBreakpointLocation sb_bp_location;
+
+ if (m_break_sp)
+ {
+ if (vm_addr != LLDB_INVALID_ADDRESS)
+ {
+ Address address;
+ Process *sb_process = m_break_sp->GetTarget().GetProcessSP().get();
+ if (sb_process == NULL || sb_process->ResolveLoadAddress (vm_addr, address) == false)
+ {
+ address.SetSection (NULL);
+ address.SetOffset (vm_addr);
+ }
+ sb_bp_location.SetLocation (m_break_sp->FindLocationByAddress (address));
+ }
+ }
+ return sb_bp_location;
+}
+
+break_id_t
+SBBreakpoint::FindLocationIDByAddress (addr_t vm_addr)
+{
+ break_id_t lldb_id = (break_id_t) 0;
+
+ if (m_break_sp)
+ {
+ if (vm_addr != LLDB_INVALID_ADDRESS)
+ {
+ Address address;
+ Process *sb_process = m_break_sp->GetTarget().GetProcessSP().get();
+ if (sb_process == NULL || sb_process->ResolveLoadAddress (vm_addr, address) == false)
+ {
+ address.SetSection (NULL);
+ address.SetOffset (vm_addr);
+ }
+ lldb_id = m_break_sp->FindLocationIDByAddress (address);
+ }
+ }
+
+ return lldb_id;
+}
+
+SBBreakpointLocation
+SBBreakpoint::FindLocationByID (break_id_t bp_loc_id)
+{
+ SBBreakpointLocation sb_bp_location;
+
+ if (m_break_sp)
+ sb_bp_location.SetLocation (m_break_sp->FindLocationByID (bp_loc_id));
+
+ return sb_bp_location;
+}
+
+SBBreakpointLocation
+SBBreakpoint::GetLocationAtIndex (uint32_t index)
+{
+ SBBreakpointLocation sb_bp_location;
+
+ if (m_break_sp)
+ sb_bp_location.SetLocation (m_break_sp->GetLocationAtIndex (index));
+
+ return sb_bp_location;
+}
+
+void
+SBBreakpoint::ListLocations (FILE* f, const char *description_level)
+{
+ if (f == NULL)
+ f = SBDebugger::GetOutputFileHandle();
+
+ if (f == NULL)
+ return;
+
+ if (m_break_sp)
+ {
+ DescriptionLevel level;
+ if (strcmp (description_level, "brief") == 0)
+ level = eDescriptionLevelBrief;
+ else if (strcmp (description_level, "full") == 0)
+ level = eDescriptionLevelFull;
+ else if (strcmp (description_level, "verbose") == 0)
+ level = eDescriptionLevelVerbose;
+ else
+ level = eDescriptionLevelBrief;
+
+ StreamFile str (f);
+
+ str.IndentMore();
+ int num_locs = m_break_sp->GetNumLocations();
+ for (int i = 0; i < num_locs; ++i)
+ {
+ BreakpointLocation *loc = m_break_sp->GetLocationAtIndex (i).get();
+ loc->GetDescription (&str, level);
+ str.EOL();
+ }
+ }
+}
+
+void
+SBBreakpoint::SetEnabled (bool enable)
+{
+ if (m_break_sp)
+ m_break_sp->SetEnabled (enable);
+}
+
+bool
+SBBreakpoint::IsEnabled ()
+{
+ if (m_break_sp)
+ return m_break_sp->IsEnabled();
+ else
+ return false;
+}
+
+void
+SBBreakpoint::SetIgnoreCount (int32_t count)
+{
+ if (m_break_sp)
+ m_break_sp->SetIgnoreCount (count);
+}
+
+int32_t
+SBBreakpoint::GetIgnoreCount () const
+{
+ if (m_break_sp)
+ return m_break_sp->GetIgnoreCount();
+ else
+ return 0;
+}
+
+void
+SBBreakpoint::SetThreadID (tid_t sb_thread_id)
+{
+ if (m_break_sp)
+ m_break_sp->SetThreadID (sb_thread_id);
+}
+
+tid_t
+SBBreakpoint::GetThreadID ()
+{
+ tid_t lldb_thread_id = LLDB_INVALID_THREAD_ID;
+ if (m_break_sp)
+ lldb_thread_id = m_break_sp->GetThreadID();
+
+ return lldb_thread_id;
+}
+
+size_t
+SBBreakpoint::GetNumResolvedLocations() const
+{
+ if (m_break_sp)
+ return m_break_sp->GetNumResolvedLocations();
+ else
+ return 0;
+}
+
+size_t
+SBBreakpoint::GetNumLocations() const
+{
+ if (m_break_sp)
+ return m_break_sp->GetNumLocations();
+ else
+ return 0;
+}
+
+void
+SBBreakpoint::GetDescription (FILE *f, const char *description_level, bool describe_locations)
+{
+ if (f == NULL)
+ return;
+
+ if (m_break_sp)
+ {
+ DescriptionLevel level;
+ if (strcmp (description_level, "brief") == 0)
+ level = eDescriptionLevelBrief;
+ else if (strcmp (description_level, "full") == 0)
+ level = eDescriptionLevelFull;
+ else if (strcmp (description_level, "verbose") == 0)
+ level = eDescriptionLevelVerbose;
+ else
+ level = eDescriptionLevelBrief;
+
+ StreamFile str (f);
+
+ m_break_sp->GetDescription (&str, level);
+ str.EOL();
+ if (describe_locations)
+ {
+ //str.IndentMore();
+ // int num_locs = m_break_sp->GetNumLocations();
+ // for (int i = 0; i < num_locs; ++i)
+ // {
+ // BreakpointLocation *loc = m_break_sp->FindLocationByIndex (i);
+ // loc->GetDescription (&str, level);
+ // str.EOL();
+ // }
+ ListLocations (f, description_level);
+ }
+ }
+}
+
+bool
+SBBreakpoint::PrivateBreakpointHitCallback
+(
+ void *baton,
+ StoppointCallbackContext *ctx,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id
+)
+{
+ BreakpointSP bp_sp(ctx->context.target->GetBreakpointList().FindBreakpointByID(break_id));
+ if (baton && bp_sp)
+ {
+ CallbackData *data = (CallbackData *)baton;
+ lldb_private::Breakpoint *bp = bp_sp.get();
+ if (bp && data->callback)
+ {
+ if (ctx->context.process)
+ {
+ SBProcess sb_process (ctx->context.process->GetSP());
+ SBThread sb_thread;
+ SBBreakpointLocation sb_location;
+ assert (bp_sp);
+ sb_location.SetLocation (bp_sp->FindLocationByID (break_loc_id));
+ if (ctx->context.thread)
+ sb_thread.SetThread(ctx->context.thread->GetSP());
+
+ 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)
+{
+ if (m_break_sp.get())
+ {
+ BatonSP baton_sp(new SBBreakpointCallbackBaton (callback, baton));
+ m_break_sp->SetCallback (SBBreakpoint::PrivateBreakpointHitCallback, baton_sp, false);
+ }
+}
+
+
+lldb_private::Breakpoint *
+SBBreakpoint::operator->() const
+{
+ return m_break_sp.get();
+}
+
+lldb_private::Breakpoint *
+SBBreakpoint::get() const
+{
+ return m_break_sp.get();
+}
+
+lldb::BreakpointSP &
+SBBreakpoint::operator *()
+{
+ return m_break_sp;
+}
+
+const lldb::BreakpointSP &
+SBBreakpoint::operator *() const
+{
+ return m_break_sp;
+}
+
diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp
new file mode 100644
index 00000000000..8bb36bd7324
--- /dev/null
+++ b/lldb/source/API/SBBreakpointLocation.cpp
@@ -0,0 +1,162 @@
+//===-- 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/SBDebugger.h"
+
+#include "lldb/lldb-types.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+//class SBBreakpointLocation
+
+SBBreakpointLocation::SBBreakpointLocation ()
+{
+}
+
+SBBreakpointLocation::SBBreakpointLocation (const lldb::BreakpointLocationSP &break_loc_sp) :
+ m_break_loc_sp (break_loc_sp)
+{
+}
+
+SBBreakpointLocation::~SBBreakpointLocation ()
+{
+}
+
+bool
+SBBreakpointLocation::IsValid() const
+{
+ return m_break_loc_sp.get() != NULL;
+}
+
+addr_t
+SBBreakpointLocation::GetLoadAddress ()
+{
+ addr_t ret_addr = LLDB_INVALID_ADDRESS;
+
+ if (m_break_loc_sp)
+ {
+ ret_addr = m_break_loc_sp->GetLoadAddress();
+ }
+
+ return ret_addr;
+}
+
+void
+SBBreakpointLocation::SetEnabled (bool enabled)
+{
+ if (m_break_loc_sp)
+ {
+ m_break_loc_sp->SetEnabled (enabled);
+ }
+}
+
+bool
+SBBreakpointLocation::IsEnabled ()
+{
+ if (m_break_loc_sp)
+ return m_break_loc_sp->IsEnabled();
+ else
+ return false;
+}
+
+int32_t
+SBBreakpointLocation::GetIgnoreCount ()
+{
+ if (m_break_loc_sp)
+ return m_break_loc_sp->GetIgnoreCount();
+ else
+ return 0;
+}
+
+void
+SBBreakpointLocation::SetIgnoreCount (int32_t n)
+{
+ if (m_break_loc_sp)
+ m_break_loc_sp->SetIgnoreCount (n);
+}
+
+void
+SBBreakpointLocation::SetThreadID (tid_t thread_id)
+{
+ if (m_break_loc_sp)
+ m_break_loc_sp->SetThreadID (thread_id);
+}
+
+tid_t
+SBBreakpointLocation::GetThreadID ()
+{
+ tid_t sb_thread_id = (lldb::tid_t) LLDB_INVALID_THREAD_ID;
+ if (m_break_loc_sp)
+ sb_thread_id = m_break_loc_sp->GetThreadID();
+
+ return sb_thread_id;
+}
+
+bool
+SBBreakpointLocation::IsResolved ()
+{
+ if (m_break_loc_sp)
+ return m_break_loc_sp->IsResolved();
+ else
+ return false;
+}
+
+void
+SBBreakpointLocation::SetLocation (const lldb::BreakpointLocationSP &break_loc_sp)
+{
+ if (m_break_loc_sp)
+ {
+ // Uninstall the callbacks?
+ }
+ m_break_loc_sp = break_loc_sp;
+}
+
+void
+SBBreakpointLocation::GetDescription (FILE *f, const char *description_level)
+{
+ if (f == NULL)
+ return;
+
+ if (m_break_loc_sp)
+ {
+ DescriptionLevel level;
+ if (strcmp (description_level, "brief") == 0)
+ level = eDescriptionLevelBrief;
+ else if (strcmp (description_level, "full") == 0)
+ level = eDescriptionLevelFull;
+ else if (strcmp (description_level, "verbose") == 0)
+ level = eDescriptionLevelVerbose;
+ else
+ level = eDescriptionLevelBrief;
+
+ StreamFile str (f);
+
+ m_break_loc_sp->GetDescription (&str, level);
+ str.EOL();
+ }
+}
+
+SBBreakpoint
+SBBreakpointLocation::GetBreakpoint ()
+{
+ SBBreakpoint sb_bp;
+ if (m_break_loc_sp)
+ *sb_bp = m_break_loc_sp->GetBreakpoint ().GetSP();
+ return sb_bp;
+}
+
diff --git a/lldb/source/API/SBBroadcaster.cpp b/lldb/source/API/SBBroadcaster.cpp
new file mode 100644
index 00000000000..b9debcfae22
--- /dev/null
+++ b/lldb/source/API/SBBroadcaster.cpp
@@ -0,0 +1,142 @@
+//===-- 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/lldb-forward-rtti.h"
+
+#include "SBBroadcaster.h"
+#include "SBListener.h"
+#include "SBEvent.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBBroadcaster::SBBroadcaster () :
+ m_lldb_object (NULL),
+ m_lldb_object_owned (false)
+{
+}
+
+
+SBBroadcaster::SBBroadcaster (const char *name) :
+ m_lldb_object (new Broadcaster (name)),
+ m_lldb_object_owned (true)
+{
+}
+
+SBBroadcaster::SBBroadcaster (lldb_private::Broadcaster *broadcaster, bool owns) :
+ m_lldb_object (broadcaster),
+ m_lldb_object_owned (owns)
+{
+}
+
+SBBroadcaster::~SBBroadcaster()
+{
+ SetLLDBObjectPtr (NULL, false);
+}
+
+void
+SBBroadcaster::BroadcastEventByType (uint32_t event_type, bool unique)
+{
+ if (m_lldb_object == NULL)
+ return;
+
+ if (unique)
+ m_lldb_object->BroadcastEventIfUnique (event_type);
+ else
+ m_lldb_object->BroadcastEvent (event_type);
+}
+
+void
+SBBroadcaster::BroadcastEvent (const SBEvent &event, bool unique)
+{
+ if (m_lldb_object == NULL)
+ return;
+
+ EventSP event_sp = event.GetSharedPtr ();
+ if (unique)
+ m_lldb_object->BroadcastEventIfUnique (event_sp);
+ else
+ m_lldb_object->BroadcastEvent (event_sp);
+}
+
+void
+SBBroadcaster::AddInitialEventsToListener (const SBListener &listener, uint32_t requested_events)
+{
+ if (m_lldb_object)
+ m_lldb_object->AddInitialEventsToListener (listener.get(), requested_events);
+}
+
+uint32_t
+SBBroadcaster::AddListener (const SBListener &listener, uint32_t event_mask)
+{
+ if (m_lldb_object)
+ return m_lldb_object->AddListener (listener.get(), event_mask);
+ return 0;
+}
+
+const char *
+SBBroadcaster::GetName ()
+{
+ if (m_lldb_object)
+ return m_lldb_object->GetBroadcasterName().AsCString();
+ return NULL;
+}
+
+bool
+SBBroadcaster::EventTypeHasListeners (uint32_t event_type)
+{
+ if (m_lldb_object)
+ return m_lldb_object->EventTypeHasListeners (event_type);
+ return false;
+}
+
+bool
+SBBroadcaster::RemoveListener (const SBListener &listener, uint32_t event_mask)
+{
+ if (m_lldb_object)
+ return m_lldb_object->RemoveListener (listener.get(), event_mask);
+ return false;
+}
+
+Broadcaster *
+SBBroadcaster::GetLLDBObjectPtr () const
+{
+ return m_lldb_object;
+}
+
+void
+SBBroadcaster::SetLLDBObjectPtr (Broadcaster *broadcaster, bool owns)
+{
+ if (m_lldb_object && m_lldb_object_owned)
+ delete m_lldb_object;
+ m_lldb_object = broadcaster;
+ m_lldb_object_owned = owns;
+}
+
+
+bool
+SBBroadcaster::IsValid () const
+{
+ return m_lldb_object != NULL;
+}
+
+bool
+SBBroadcaster::operator == (const SBBroadcaster &rhs) const
+{
+ return m_lldb_object == rhs.m_lldb_object;
+
+}
+
+bool
+SBBroadcaster::operator != (const SBBroadcaster &rhs) const
+{
+ return m_lldb_object != rhs.m_lldb_object;
+}
diff --git a/lldb/source/API/SBCommandContext.cpp b/lldb/source/API/SBCommandContext.cpp
new file mode 100644
index 00000000000..3a1b60aa314
--- /dev/null
+++ b/lldb/source/API/SBCommandContext.cpp
@@ -0,0 +1,34 @@
+//===-- SBCommandContext.cpp ------------------------------------*- 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/CommandContext.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+#include "SBCommandContext.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBCommandContext::SBCommandContext (CommandContext *lldb_object) :
+ m_lldb_object (lldb_object)
+{
+}
+
+SBCommandContext::~SBCommandContext ()
+{
+}
+
+bool
+SBCommandContext::IsValid () const
+{
+ return m_lldb_object != NULL;
+}
+
diff --git a/lldb/source/API/SBCommandInterpreter.cpp b/lldb/source/API/SBCommandInterpreter.cpp
new file mode 100644
index 00000000000..1e40320ad60
--- /dev/null
+++ b/lldb/source/API/SBCommandInterpreter.cpp
@@ -0,0 +1,193 @@
+//===-- 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-types.h"
+#include "lldb/Core/Args.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Target.h"
+
+#include "SBBroadcaster.h"
+#include "SBDebugger.h"
+#include "SBCommandReturnObject.h"
+#include "SBCommandContext.h"
+#include "SBSourceManager.h"
+#include "SBCommandInterpreter.h"
+#include "SBProcess.h"
+#include "SBTarget.h"
+#include "SBListener.h"
+#include "SBStringList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBCommandInterpreter::SBCommandInterpreter (CommandInterpreter &interpreter) :
+ m_interpreter (interpreter)
+{
+}
+
+SBCommandInterpreter::~SBCommandInterpreter ()
+{
+}
+
+bool
+SBCommandInterpreter::CommandExists (const char *cmd)
+{
+ return m_interpreter.CommandExists (cmd);
+}
+
+bool
+SBCommandInterpreter::AliasExists (const char *cmd)
+{
+ return m_interpreter.AliasExists (cmd);
+}
+
+bool
+SBCommandInterpreter::UserCommandExists (const char *cmd)
+{
+ return m_interpreter.UserCommandExists (cmd);
+}
+
+lldb::ReturnStatus
+SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnObject &result, bool add_to_history)
+{
+ result.Clear();
+ m_interpreter.HandleCommand (command_line, add_to_history, result.GetLLDBObjectRef());
+ 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)
+{
+ int num_completions;
+ lldb_private::StringList lldb_matches;
+ num_completions = m_interpreter.HandleCompletion (current_line, cursor, last_char, match_start_point,
+ max_return_elements, lldb_matches);
+
+ SBStringList temp_list (&lldb_matches);
+ matches.AppendList (temp_list);
+
+ return num_completions;
+}
+
+const char **
+SBCommandInterpreter::GetEnvironmentVariables ()
+{
+ const Args *env_vars = m_interpreter.GetEnvironmentVariables();
+ if (env_vars)
+ return env_vars->GetConstArgumentVector ();
+ return NULL;
+}
+
+bool
+SBCommandInterpreter::HasCommands ()
+{
+ return m_interpreter.HasCommands();
+}
+
+bool
+SBCommandInterpreter::HasAliases ()
+{
+ return m_interpreter.HasAliases();
+}
+
+bool
+SBCommandInterpreter::HasUserCommands ()
+{
+ return m_interpreter.HasUserCommands ();
+}
+
+bool
+SBCommandInterpreter::HasAliasOptions ()
+{
+ return m_interpreter.HasAliasOptions ();
+}
+
+bool
+SBCommandInterpreter::HasInterpreterVariables ()
+{
+ return m_interpreter.HasInterpreterVariables ();
+}
+
+SBProcess
+SBCommandInterpreter::GetProcess ()
+{
+ SBProcess process;
+ CommandContext *context = m_interpreter.Context();
+ if (context)
+ {
+ Target *target = context->GetTarget();
+ if (target)
+ process.SetProcess(target->GetProcessSP());
+ }
+ return process;
+}
+
+ssize_t
+SBCommandInterpreter::WriteToScriptInterpreter (const char *src)
+{
+ if (src)
+ return WriteToScriptInterpreter (src, strlen(src));
+ return 0;
+}
+
+ssize_t
+SBCommandInterpreter::WriteToScriptInterpreter (const char *src, size_t src_len)
+{
+ if (src && src[0])
+ {
+ ScriptInterpreter *script_interpreter = m_interpreter.GetScriptInterpreter();
+ if (script_interpreter)
+ return ::write (script_interpreter->GetMasterFileDescriptor(), src, src_len);
+ }
+ return 0;
+}
+
+
+CommandInterpreter *
+SBCommandInterpreter::GetLLDBObjectPtr ()
+{
+ return &m_interpreter;
+}
+
+CommandInterpreter &
+SBCommandInterpreter::GetLLDBObjectRef ()
+{
+ return m_interpreter;
+}
+
+void
+SBCommandInterpreter::SourceInitFileInHomeDirectory (SBCommandReturnObject &result)
+{
+ result.Clear();
+ m_interpreter.SourceInitFile (false, result.GetLLDBObjectRef());
+}
+
+void
+SBCommandInterpreter::SourceInitFileInCurrentWorkingDirectory (SBCommandReturnObject &result)
+{
+ result.Clear();
+ m_interpreter.SourceInitFile (true, result.GetLLDBObjectRef());
+}
+
+SBBroadcaster
+SBCommandInterpreter::GetBroadcaster ()
+{
+ SBBroadcaster broadcaster (&m_interpreter, false);
+ return broadcaster;
+}
+
diff --git a/lldb/source/API/SBCommandReturnObject.cpp b/lldb/source/API/SBCommandReturnObject.cpp
new file mode 100644
index 00000000000..3910cc4b03d
--- /dev/null
+++ b/lldb/source/API/SBCommandReturnObject.cpp
@@ -0,0 +1,148 @@
+//===-- 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/Interpreter/CommandReturnObject.h"
+
+#include "SBCommandReturnObject.h"
+
+using namespace lldb;
+
+SBCommandReturnObject::SBCommandReturnObject () :
+ m_return_object_ap (new lldb_private::CommandReturnObject ())
+{
+}
+
+SBCommandReturnObject::~SBCommandReturnObject ()
+{
+ // m_return_object_ap will automatically delete any pointer it owns
+}
+
+bool
+SBCommandReturnObject::IsValid() const
+{
+ return m_return_object_ap.get() != NULL;
+}
+
+
+const char *
+SBCommandReturnObject::GetOutput ()
+{
+ if (m_return_object_ap.get())
+ return m_return_object_ap->GetOutputStream().GetData();
+ return NULL;
+}
+
+const char *
+SBCommandReturnObject::GetError ()
+{
+ if (m_return_object_ap.get())
+ return m_return_object_ap->GetErrorStream().GetData();
+ return NULL;
+}
+
+size_t
+SBCommandReturnObject::GetOutputSize ()
+{
+ if (m_return_object_ap.get())
+ return m_return_object_ap->GetOutputStream().GetSize();
+ return 0;
+}
+
+size_t
+SBCommandReturnObject::GetErrorSize ()
+{
+ if (m_return_object_ap.get())
+ return m_return_object_ap->GetErrorStream().GetSize();
+ 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_return_object_ap.get())
+ m_return_object_ap->Clear();
+}
+
+lldb::ReturnStatus
+SBCommandReturnObject::GetStatus()
+{
+ if (m_return_object_ap.get())
+ return m_return_object_ap->GetStatus();
+ return lldb::eReturnStatusInvalid;
+}
+
+bool
+SBCommandReturnObject::Succeeded ()
+{
+ if (m_return_object_ap.get())
+ return m_return_object_ap->Succeeded();
+ return false;
+}
+
+bool
+SBCommandReturnObject::HasResult ()
+{
+ if (m_return_object_ap.get())
+ return m_return_object_ap->HasResult();
+ return false;
+}
+
+void
+SBCommandReturnObject::AppendMessage (const char *message)
+{
+ if (m_return_object_ap.get())
+ m_return_object_ap->AppendMessage (message);
+}
+
+lldb_private::CommandReturnObject *
+SBCommandReturnObject::GetLLDBObjectPtr()
+{
+ return m_return_object_ap.get();
+}
+
+
+lldb_private::CommandReturnObject &
+SBCommandReturnObject::GetLLDBObjectRef()
+{
+ assert(m_return_object_ap.get());
+ return *(m_return_object_ap.get());
+}
+
+
+void
+SBCommandReturnObject::SetLLDBObjectPtr (lldb_private::CommandReturnObject *ptr)
+{
+ if (m_return_object_ap.get())
+ m_return_object_ap.reset (ptr);
+}
+
diff --git a/lldb/source/API/SBCommunication.cpp b/lldb/source/API/SBCommunication.cpp
new file mode 100644
index 00000000000..e2a791750a8
--- /dev/null
+++ b/lldb/source/API/SBCommunication.cpp
@@ -0,0 +1,194 @@
+//===-- 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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+SBCommunication::SBCommunication() :
+ m_lldb_object (NULL),
+ m_lldb_object_owned (false)
+{
+}
+
+SBCommunication::SBCommunication(const char * broadcaster_name) :
+ m_lldb_object (new Communication (broadcaster_name)),
+ m_lldb_object_owned (true)
+{
+}
+
+SBCommunication::~SBCommunication()
+{
+ if (m_lldb_object && m_lldb_object_owned)
+ delete m_lldb_object;
+ m_lldb_object = NULL;
+ m_lldb_object_owned = false;
+}
+
+ConnectionStatus
+SBCommunication::CheckIfBytesAvailable ()
+{
+ if (m_lldb_object)
+ return m_lldb_object->BytesAvailable (0, NULL);
+ return eConnectionStatusNoConnection;
+}
+
+ConnectionStatus
+SBCommunication::WaitForBytesAvailableInfinite ()
+{
+ if (m_lldb_object)
+ return m_lldb_object->BytesAvailable (UINT32_MAX, NULL);
+ return eConnectionStatusNoConnection;
+}
+
+ConnectionStatus
+SBCommunication::WaitForBytesAvailableWithTimeout (uint32_t timeout_usec)
+{
+ if (m_lldb_object)
+ return m_lldb_object->BytesAvailable (timeout_usec, NULL);
+ return eConnectionStatusNoConnection;
+}
+
+ConnectionStatus
+SBCommunication::Connect (const char *url)
+{
+ if (m_lldb_object)
+ {
+ if (!m_lldb_object->HasConnection ())
+ m_lldb_object->SetConnection (new ConnectionFileDescriptor());
+ return m_lldb_object->Connect (url, NULL);
+ }
+ return eConnectionStatusNoConnection;
+}
+
+ConnectionStatus
+SBCommunication::AdoptFileDesriptor (int fd, bool owns_fd)
+{
+ if (m_lldb_object)
+ {
+ if (m_lldb_object->HasConnection ())
+ {
+ if (m_lldb_object->IsConnected())
+ m_lldb_object->Disconnect ();
+ }
+ m_lldb_object->SetConnection (new ConnectionFileDescriptor (fd, owns_fd));
+ if (m_lldb_object->IsConnected())
+ return eConnectionStatusSuccess;
+ else
+ return eConnectionStatusLostConnection;
+ }
+ return eConnectionStatusNoConnection;
+}
+
+
+ConnectionStatus
+SBCommunication::Disconnect ()
+{
+ if (m_lldb_object)
+ return m_lldb_object->Disconnect ();
+ return eConnectionStatusNoConnection;
+}
+
+bool
+SBCommunication::IsConnected () const
+{
+ if (m_lldb_object)
+ return m_lldb_object->IsConnected ();
+ return false;
+}
+
+size_t
+SBCommunication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status)
+{
+ if (m_lldb_object)
+ return m_lldb_object->Read (dst, dst_len, timeout_usec, status, NULL);
+ status = eConnectionStatusNoConnection;
+ return 0;
+}
+
+
+size_t
+SBCommunication::Write (const void *src, size_t src_len, ConnectionStatus &status)
+{
+ if (m_lldb_object)
+ return m_lldb_object->Write (src, src_len, status, NULL);
+ status = eConnectionStatusNoConnection;
+ return 0;
+}
+
+bool
+SBCommunication::ReadThreadStart ()
+{
+ if (m_lldb_object)
+ return m_lldb_object->StartReadThread ();
+ return false;
+}
+
+
+bool
+SBCommunication::ReadThreadStop ()
+{
+ if (m_lldb_object)
+ return m_lldb_object->StopReadThread ();
+ return false;
+}
+
+bool
+SBCommunication::ReadThreadIsRunning ()
+{
+ if (m_lldb_object)
+ return m_lldb_object->ReadThreadIsRunning ();
+ return false;
+}
+
+bool
+SBCommunication::SetReadThreadBytesReceivedCallback
+(
+ ReadThreadBytesReceived callback,
+ void *callback_baton
+)
+{
+ if (m_lldb_object)
+ {
+ m_lldb_object->SetReadThreadBytesReceivedCallback (callback, callback_baton);
+ return true;
+ }
+ return false;
+}
+
+SBBroadcaster
+SBCommunication::GetBroadcaster ()
+{
+ SBBroadcaster broadcaster (m_lldb_object, false);
+ return broadcaster;
+}
+
+
+//
+//void
+//SBCommunication::CreateIfNeeded ()
+//{
+// if (m_lldb_object == NULL)
+// {
+// static uint32_t g_broadcaster_num;
+// char broadcaster_name[256];
+// ::snprintf (name, broadcaster_name, "%p SBCommunication", this);
+// m_lldb_object = new Communication (broadcaster_name);
+// m_lldb_object_owned = true;
+// }
+// assert (m_lldb_object);
+//}
+//
+//
diff --git a/lldb/source/API/SBCompileUnit.cpp b/lldb/source/API/SBCompileUnit.cpp
new file mode 100644
index 00000000000..a12934a0587
--- /dev/null
+++ b/lldb/source/API/SBCompileUnit.cpp
@@ -0,0 +1,120 @@
+//===-- 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/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineEntry.h"
+#include "lldb/Symbol/LineTable.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBCompileUnit::SBCompileUnit () :
+ m_lldb_object_ptr (NULL)
+{
+}
+
+SBCompileUnit::SBCompileUnit (lldb_private::CompileUnit *lldb_object_ptr) :
+ m_lldb_object_ptr (lldb_object_ptr)
+{
+}
+
+SBCompileUnit::~SBCompileUnit ()
+{
+ m_lldb_object_ptr = NULL;
+}
+
+SBFileSpec
+SBCompileUnit::GetFileSpec () const
+{
+ SBFileSpec file_spec;
+ if (m_lldb_object_ptr)
+ file_spec.SetFileSpec(*m_lldb_object_ptr);
+ return file_spec;
+}
+
+uint32_t
+SBCompileUnit::GetNumLineEntries () const
+{
+ if (m_lldb_object_ptr)
+ {
+ LineTable *line_table = m_lldb_object_ptr->GetLineTable ();
+ if (line_table)
+ return line_table->GetSize();
+ }
+ return 0;
+}
+
+SBLineEntry
+SBCompileUnit::GetLineEntryAtIndex (uint32_t idx) const
+{
+ SBLineEntry sb_line_entry;
+ if (m_lldb_object_ptr)
+ {
+ LineTable *line_table = m_lldb_object_ptr->GetLineTable ();
+ if (line_table)
+ {
+ LineEntry line_entry;
+ if (line_table->GetLineEntryAtIndex(idx, line_entry))
+ sb_line_entry.SetLineEntry(line_entry);
+ }
+ }
+ return sb_line_entry;
+}
+
+uint32_t
+SBCompileUnit::FindLineEntryIndex (uint32_t start_idx, uint32_t line, SBFileSpec *inline_file_spec) const
+{
+ if (m_lldb_object_ptr)
+ {
+ FileSpec file_spec;
+ if (inline_file_spec && inline_file_spec->IsValid())
+ file_spec = inline_file_spec->ref();
+ else
+ file_spec = *m_lldb_object_ptr;
+
+ return m_lldb_object_ptr->FindLineEntry (start_idx,
+ line,
+ inline_file_spec ? inline_file_spec->get() : NULL,
+ NULL);
+ }
+ return UINT32_MAX;
+}
+
+bool
+SBCompileUnit::IsValid () const
+{
+ return m_lldb_object_ptr != NULL;
+}
+
+bool
+SBCompileUnit::operator == (const SBCompileUnit &rhs) const
+{
+ return m_lldb_object_ptr == rhs.m_lldb_object_ptr;
+}
+
+bool
+SBCompileUnit::operator != (const SBCompileUnit &rhs) const
+{
+ return m_lldb_object_ptr != rhs.m_lldb_object_ptr;
+}
+
+const lldb_private::CompileUnit *
+SBCompileUnit::operator->() const
+{
+ return m_lldb_object_ptr;
+}
+
+const lldb_private::CompileUnit &
+SBCompileUnit::operator*() const
+{
+ return *m_lldb_object_ptr;
+}
diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
new file mode 100644
index 00000000000..d31c93cddb8
--- /dev/null
+++ b/lldb/source/API/SBDebugger.cpp
@@ -0,0 +1,569 @@
+//===-- 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 "SBDebugger.h"
+
+#include "lldb/lldb-include.h"
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/TargetList.h"
+
+#include "SBListener.h"
+#include "SBBroadcaster.h"
+#include "SBCommandInterpreter.h"
+#include "SBCommandReturnObject.h"
+#include "SBEvent.h"
+#include "SBFrame.h"
+#include "SBTarget.h"
+#include "SBProcess.h"
+#include "SBThread.h"
+#include "SBSourceManager.h"
+#include "SBInputReader.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+SBDebugger::Initialize ()
+{
+ Debugger::Initialize();
+}
+
+void
+SBDebugger::Terminate ()
+{
+ Debugger::Terminate();
+}
+
+void
+SBDebugger::SetAsync (bool b)
+{
+ static bool value_set_once = false;
+
+ if (!value_set_once)
+ {
+ value_set_once = true;
+ Debugger::GetSharedInstance().SetAsyncExecution(b);
+ }
+}
+
+void
+SBDebugger::SetInputFile (const char *tty_name)
+{
+ // DEPRECATED: will be removed in next submission
+ FILE *fh = ::fopen (tty_name, "r");
+ SetInputFileHandle (fh, true);
+}
+
+void
+SBDebugger::SetOutputFile (const char *tty_name)
+{
+ // DEPRECATED: will be removed in next submission
+ FILE *fh = ::fopen (tty_name, "w");
+ SetOutputFileHandle (fh, true);
+ SetErrorFileHandle (fh, false);
+}
+
+void
+SBDebugger::SetErrorFile (const char *tty_name)
+{
+ // DEPRECATED: will be removed in next submission
+}
+
+
+// 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)
+{
+ Debugger::GetSharedInstance().SetInputFileHandle (fh, transfer_ownership);
+}
+
+void
+SBDebugger::SetOutputFileHandle (FILE *fh, bool transfer_ownership)
+{
+ Debugger::GetSharedInstance().SetOutputFileHandle (fh, transfer_ownership);
+}
+
+void
+SBDebugger::SetErrorFileHandle (FILE *fh, bool transfer_ownership)
+{
+ Debugger::GetSharedInstance().SetErrorFileHandle (fh, transfer_ownership);
+}
+
+FILE *
+SBDebugger::GetInputFileHandle ()
+{
+ return Debugger::GetSharedInstance().GetInputFileHandle();
+}
+
+FILE *
+SBDebugger::GetOutputFileHandle ()
+{
+ return Debugger::GetSharedInstance().GetOutputFileHandle();
+}
+
+FILE *
+SBDebugger::GetErrorFileHandle ()
+{
+ return Debugger::GetSharedInstance().GetErrorFileHandle();
+}
+
+SBCommandInterpreter
+SBDebugger::GetCommandInterpreter ()
+{
+ SBCommandInterpreter sb_interpreter(Debugger::GetSharedInstance().GetCommandInterpreter());
+ return sb_interpreter;
+}
+
+void
+SBDebugger::HandleCommand (const char *command)
+{
+ SBProcess process;
+ SBCommandInterpreter sb_interpreter(Debugger::GetSharedInstance().GetCommandInterpreter());
+ SBCommandReturnObject result;
+
+ sb_interpreter.HandleCommand (command, result, false);
+
+ if (GetErrorFileHandle() != NULL)
+ result.PutError (GetErrorFileHandle());
+ if (GetOutputFileHandle() != NULL)
+ result.PutOutput (GetOutputFileHandle());
+
+ if (Debugger::GetSharedInstance().GetAsyncExecution() == false)
+ {
+ process = GetCommandInterpreter().GetProcess ();
+ if (process.IsValid())
+ {
+ EventSP event_sp;
+ Listener &lldb_listener = Debugger::GetSharedInstance().GetListener();
+ while (lldb_listener.GetNextEventForBroadcaster (process.get(), event_sp))
+ {
+ SBEvent event(event_sp);
+ HandleProcessEvent (process, event, GetOutputFileHandle(), GetErrorFileHandle());
+ }
+ }
+ }
+}
+
+SBListener
+SBDebugger::GetListener ()
+{
+ SBListener sb_listener(Debugger::GetSharedInstance().GetListener());
+ return sb_listener;
+}
+
+void
+SBDebugger::HandleProcessEvent (const SBProcess &process, const SBEvent &event, FILE *out, FILE *err)
+{
+ const uint32_t event_type = event.GetType();
+ char stdio_buffer[1024];
+ size_t len;
+
+ if (event_type & Process::eBroadcastBitSTDOUT)
+ {
+ while ((len = process.GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
+ if (out != NULL)
+ ::fwrite (stdio_buffer, 1, len, out);
+ }
+ else if (event_type & Process::eBroadcastBitSTDERR)
+ {
+ while ((len = process.GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
+ if (out != NULL)
+ ::fwrite (stdio_buffer, 1, len, out);
+ }
+ else if (event_type & Process::eBroadcastBitStateChanged)
+ {
+ // Drain any stdout messages.
+ while ((len = process.GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
+ if (out != NULL)
+ ::fwrite (stdio_buffer, 1, len, out);
+
+ // Drain any stderr messages.
+ while ((len = process.GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
+ if (out != NULL)
+ ::fwrite (stdio_buffer, 1, len, out);
+
+ StateType event_state = SBProcess::GetStateFromEvent (event);
+
+ if (event_state == eStateInvalid)
+ return;
+
+ bool is_stopped = StateIsStoppedState (event_state);
+ if (!is_stopped)
+ process.ReportCurrentState (event, out);
+ }
+}
+
+void
+SBDebugger::UpdateCurrentThread (SBProcess &process)
+{
+ if (process.IsValid())
+ {
+ SBThread curr_thread = process.GetCurrentThread ();
+ SBThread thread;
+ StopReason curr_thread_stop_reason = eStopReasonInvalid;
+ if (curr_thread.IsValid())
+ {
+ if (curr_thread.GetStopReason() != 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);
+ if (thread.GetStopReason () != eStopReasonInvalid)
+ {
+ switch (thread.GetStopReason ())
+ {
+ default:
+ case eStopReasonInvalid:
+ case eStopReasonNone:
+ break;
+
+ case eStopReasonTrace:
+ case eStopReasonBreakpoint:
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ if (! other_thread.IsValid())
+ other_thread = thread;
+ break;
+ case eStopReasonPlanComplete:
+ if (! plan_thread.IsValid())
+ plan_thread = thread;
+ break;
+ }
+ }
+ }
+ if (plan_thread.IsValid())
+ process.SetCurrentThreadByID (plan_thread.GetThreadID());
+ else if (other_thread.IsValid())
+ process.SetCurrentThreadByID (other_thread.GetThreadID());
+ else
+ {
+ if (curr_thread.IsValid())
+ thread = curr_thread;
+ else
+ thread = process.GetThreadAtIndex(0);
+
+ if (thread.IsValid())
+ process.SetCurrentThreadByID (thread.GetThreadID());
+ }
+ }
+ }
+}
+
+void
+SBDebugger::ReportCurrentLocation (FILE *out, FILE *err)
+{
+ if ((out == NULL) || (err == NULL))
+ return;
+
+ SBTarget sb_target (GetCurrentTarget());
+ if (!sb_target.IsValid())
+ {
+ fprintf (out, "no target\n");
+ return;
+ }
+
+ SBProcess process = sb_target.GetProcess ();
+ if (process.IsValid())
+ {
+ StateType state = process.GetState();
+
+ if (StateIsStoppedState (state))
+ {
+ if (state == eStateExited)
+ {
+ int exit_status = process.GetExitStatus();
+ const char *exit_description = process.GetExitDescription();
+ ::fprintf (out, "Process %d exited with status = %i (0x%8.8x) %s\n",
+ process.GetProcessID(),
+ exit_status,
+ exit_status,
+ exit_description ? exit_description : "");
+ }
+ else
+ {
+ fprintf (out, "Process %d %s\n", process.GetProcessID(), StateAsCString (state));
+ SBThread current_thread = process.GetThreadAtIndex (0);
+ if (current_thread.IsValid())
+ {
+ process.DisplayThreadsInfo (out, err, true);
+ }
+ else
+ fprintf (out, "No valid thread found in current process\n");
+ }
+ }
+ else
+ fprintf (out, "No current location or status available\n");
+ }
+}
+
+SBSourceManager &
+SBDebugger::GetSourceManager ()
+{
+ static SourceManager g_lldb_source_manager;
+ static SBSourceManager g_sb_source_manager (g_lldb_source_manager);
+ return g_sb_source_manager;
+}
+
+
+bool
+SBDebugger::GetDefaultArchitecture (char *arch_name, size_t arch_name_len)
+{
+ if (arch_name && arch_name_len)
+ {
+ ArchSpec &default_arch = lldb_private::GetDefaultArchitecture ();
+ if (default_arch.IsValid())
+ {
+ ::snprintf (arch_name, arch_name_len, "%s", default_arch.AsCString());
+ 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())
+ {
+ lldb_private::GetDefaultArchitecture () = arch;
+ return true;
+ }
+ }
+ return false;
+}
+
+ScriptLanguage
+SBDebugger::GetScriptingLanguage (const char *script_language_name)
+{
+ return Args::StringToScriptLanguage (script_language_name,
+ eScriptLanguageDefault,
+ NULL);
+}
+//pid_t
+/*
+SBDebugger::AttachByName (const char *process_name, const char *filename)
+{
+ SBTarget *temp_target = GetCurrentTarget();
+ SBTarget sb_target;
+ pid_t return_pid = (pid_t) LLDB_INVALID_PROCESS_ID;
+
+ if (temp_target == NULL)
+ {
+ if (filename != NULL)
+ {
+ sb_target = CreateWithFile (filename);
+ sb_target.SetArch (LLDB_ARCH_DEFAULT);
+ }
+ }
+ else
+ {
+ sb_target = *temp_target;
+ }
+
+ if (sb_target.IsValid())
+ {
+ SBProcess process = sb_target.GetProcess ();
+ if (process.IsValid())
+ {
+ return_pid = process.AttachByName (process_name);
+ }
+ }
+ return return_pid;
+}
+*/
+
+const char *
+SBDebugger::GetVersionString ()
+{
+ return lldb_private::GetVersion();
+}
+
+const char *
+SBDebugger::StateAsCString (lldb::StateType state)
+{
+ return lldb_private::StateAsCString (state);
+}
+
+bool
+SBDebugger::StateIsRunningState (lldb::StateType state)
+{
+ return lldb_private::StateIsRunningState (state);
+}
+
+bool
+SBDebugger::StateIsStoppedState (lldb::StateType state)
+{
+ return lldb_private::StateIsStoppedState (state);
+}
+
+
+SBTarget
+SBDebugger::CreateTargetWithFileAndTargetTriple (const char *filename,
+ const char *target_triple)
+{
+ ArchSpec arch;
+ FileSpec file_spec (filename);
+ arch.SetArchFromTargetTriple(target_triple);
+ TargetSP target_sp;
+ Error error (Debugger::GetSharedInstance().GetTargetList().CreateTarget (file_spec, arch, NULL, true, target_sp));
+ SBTarget target(target_sp);
+ return target;
+}
+
+SBTarget
+SBDebugger::CreateTargetWithFileAndArch (const char *filename, const char *archname)
+{
+ FileSpec file (filename);
+ ArchSpec arch = lldb_private::GetDefaultArchitecture();
+ TargetSP target_sp;
+ Error error;
+
+ if (archname != NULL)
+ {
+ ArchSpec arch2 (archname);
+ error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file, arch2, NULL, true, target_sp);
+ }
+ else
+ {
+ if (!arch.IsValid())
+ arch = LLDB_ARCH_DEFAULT;
+
+ error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file, arch, NULL, true, target_sp);
+
+ if (error.Fail())
+ {
+ if (arch == LLDB_ARCH_DEFAULT_32BIT)
+ arch = LLDB_ARCH_DEFAULT_64BIT;
+ else
+ arch = LLDB_ARCH_DEFAULT_32BIT;
+
+ error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file, arch, NULL, true, target_sp);
+ }
+ }
+
+ if (error.Success())
+ Debugger::GetSharedInstance().GetTargetList().SetCurrentTarget (target_sp.get());
+ else
+ target_sp.reset();
+
+ SBTarget sb_target (target_sp);
+ return sb_target;
+}
+
+SBTarget
+SBDebugger::CreateTarget (const char *filename)
+{
+ FileSpec file (filename);
+ ArchSpec arch = lldb_private::GetDefaultArchitecture();
+ TargetSP target_sp;
+ Error error;
+
+ if (!arch.IsValid())
+ arch = LLDB_ARCH_DEFAULT;
+
+ error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file, arch, NULL, true, target_sp);
+
+ if (error.Fail())
+ {
+ if (arch == LLDB_ARCH_DEFAULT_32BIT)
+ arch = LLDB_ARCH_DEFAULT_64BIT;
+ else
+ arch = LLDB_ARCH_DEFAULT_32BIT;
+
+ error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file, arch, NULL, true, target_sp);
+ }
+
+ if (!error.Fail())
+ Debugger::GetSharedInstance().GetTargetList().SetCurrentTarget (target_sp.get());
+
+ SBTarget sb_target (target_sp);
+ return sb_target;
+}
+
+SBTarget
+SBDebugger::GetTargetAtIndex (uint32_t idx)
+{
+ SBTarget sb_target (Debugger::GetSharedInstance().GetTargetList().GetTargetAtIndex (idx));
+ return sb_target;
+}
+
+SBTarget
+SBDebugger::FindTargetWithProcessID (pid_t pid)
+{
+ SBTarget sb_target(Debugger::GetSharedInstance().GetTargetList().FindTargetWithProcessID (pid));
+ return sb_target;
+}
+
+SBTarget
+SBDebugger::FindTargetWithFileAndArch (const char *filename, const char *arch_name)
+{
+ ArchSpec arch;
+ if (arch_name)
+ arch.SetArch(arch_name);
+ return SBTarget (Debugger::GetSharedInstance().GetTargetList().FindTargetWithExecutableAndArchitecture (FileSpec(filename),
+ arch_name ? &arch : NULL));
+}
+
+SBTarget
+SBDebugger::FindTargetWithLLDBProcess (const lldb::ProcessSP &process_sp)
+{
+ SBTarget sb_target(Debugger::GetSharedInstance().GetTargetList().FindTargetWithProcess (process_sp.get()));
+ return sb_target;
+}
+
+
+uint32_t
+SBDebugger::GetNumTargets ()
+{
+ return Debugger::GetSharedInstance().GetTargetList().GetNumTargets ();}
+
+SBTarget
+SBDebugger::GetCurrentTarget ()
+{
+ SBTarget sb_target(Debugger::GetSharedInstance().GetTargetList().GetCurrentTarget ());
+ return sb_target;
+}
+
+void
+SBDebugger::DispatchInput (void *baton, const void *data, size_t data_len)
+{
+ Debugger::GetSharedInstance().DispatchInput ((const char *) data, data_len);
+}
+
+void
+SBDebugger::PushInputReader (SBInputReader &reader)
+{
+ if (reader.IsValid())
+ {
+ InputReaderSP reader_sp(*reader);
+ Debugger::GetSharedInstance().PushInputReader (reader_sp);
+ }
+}
diff --git a/lldb/source/API/SBError.cpp b/lldb/source/API/SBError.cpp
new file mode 100644
index 00000000000..7c257c94b37
--- /dev/null
+++ b/lldb/source/API/SBError.cpp
@@ -0,0 +1,179 @@
+//===-- 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/Core/Error.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBError::SBError () :
+ m_lldb_object_ap ()
+{
+}
+
+SBError::SBError (const SBError &rhs) :
+ m_lldb_object_ap ()
+{
+ if (rhs.IsValid())
+ m_lldb_object_ap.reset (new Error(*rhs));
+}
+
+
+SBError::~SBError()
+{
+}
+
+const SBError &
+SBError::operator = (const SBError &rhs)
+{
+ if (rhs.IsValid())
+ {
+ if (m_lldb_object_ap.get())
+ *m_lldb_object_ap = *rhs;
+ else
+ m_lldb_object_ap.reset (new Error(*rhs));
+ }
+ else
+ {
+ m_lldb_object_ap.reset();
+ }
+ return *this;
+}
+
+
+const char *
+SBError::GetCString () const
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->AsCString();
+ return NULL;
+}
+
+void
+SBError::Clear ()
+{
+ if (m_lldb_object_ap.get())
+ m_lldb_object_ap->Clear();
+}
+
+bool
+SBError::Fail () const
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->Fail();
+ return false;
+}
+
+bool
+SBError::Success () const
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->Success();
+ return false;
+}
+
+uint32_t
+SBError::GetError () const
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->GetError();
+ return true;
+}
+
+ErrorType
+SBError::GetType () const
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->GetType();
+ return eErrorTypeInvalid;
+}
+
+void
+SBError::SetError (uint32_t err, ErrorType type)
+{
+ CreateIfNeeded ();
+ m_lldb_object_ap->SetError (err, type);
+}
+
+void
+SBError::SetError (const Error &lldb_error)
+{
+ CreateIfNeeded ();
+ *m_lldb_object_ap = lldb_error;
+}
+
+
+void
+SBError::SetErrorToErrno ()
+{
+ CreateIfNeeded ();
+ m_lldb_object_ap->SetErrorToErrno ();
+}
+
+void
+SBError::SetErrorToGenericError ()
+{
+ CreateIfNeeded ();
+ m_lldb_object_ap->SetErrorToErrno ();
+}
+
+void
+SBError::SetErrorString (const char *err_str)
+{
+ CreateIfNeeded ();
+ m_lldb_object_ap->SetErrorString (err_str);
+}
+
+int
+SBError::SetErrorStringWithFormat (const char *format, ...)
+{
+ CreateIfNeeded ();
+ va_list args;
+ va_start (args, format);
+ int num_chars = m_lldb_object_ap->SetErrorStringWithVarArg (format, args);
+ va_end (args);
+ return num_chars;
+}
+
+bool
+SBError::IsValid () const
+{
+ return m_lldb_object_ap.get() != NULL;
+}
+
+void
+SBError::CreateIfNeeded ()
+{
+ if (m_lldb_object_ap.get() == NULL)
+ m_lldb_object_ap.reset(new Error ());
+}
+
+
+lldb_private::Error *
+SBError::operator->()
+{
+ return m_lldb_object_ap.get();
+}
+
+lldb_private::Error *
+SBError::get()
+{
+ return m_lldb_object_ap.get();
+}
+
+
+const lldb_private::Error &
+SBError::operator*() const
+{
+ // Be sure to call "IsValid()" before calling this function or it will crash
+ return *m_lldb_object_ap;
+}
+
diff --git a/lldb/source/API/SBEvent.cpp b/lldb/source/API/SBEvent.cpp
new file mode 100644
index 00000000000..c69957ebefc
--- /dev/null
+++ b/lldb/source/API/SBEvent.cpp
@@ -0,0 +1,176 @@
+//===-- 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 "SBEvent.h"
+#include "SBBroadcaster.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_lldb_object (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_lldb_object (m_event_sp.get())
+{
+}
+
+SBEvent::SBEvent (EventSP &event_sp) :
+ m_event_sp (event_sp),
+ m_lldb_object (event_sp.get())
+{
+}
+
+SBEvent::~SBEvent()
+{
+}
+
+void
+SBEvent::Dump (FILE *f) const
+{
+ const Event *lldb_event = GetLLDBObjectPtr();
+ if (lldb_event)
+ {
+ StreamFile str(f);
+ lldb_event->Dump ((Stream *) &str);
+ }
+}
+
+const char *
+SBEvent::GetDataFlavor ()
+{
+ Event *lldb_event = SBEvent::GetLLDBObjectPtr();
+ if (lldb_event)
+ return lldb_event->GetData()->GetFlavor().AsCString();
+ return NULL;
+}
+
+uint32_t
+SBEvent::GetType () const
+{
+ const Event *lldb_event = SBEvent::GetLLDBObjectPtr();
+ if (lldb_event)
+ return lldb_event->GetType();
+ return 0;
+}
+
+SBBroadcaster
+SBEvent::GetBroadcaster () const
+{
+ SBBroadcaster broadcaster;
+ const Event *lldb_event = SBEvent::GetLLDBObjectPtr();
+ if (lldb_event)
+ broadcaster.SetLLDBObjectPtr (lldb_event->GetBroadcaster(), false);
+ return broadcaster;
+}
+
+bool
+SBEvent::BroadcasterMatchesPtr (const SBBroadcaster *broadcaster)
+{
+ if (broadcaster)
+ {
+ Event *lldb_event = SBEvent::GetLLDBObjectPtr();
+ if (lldb_event)
+ return lldb_event->BroadcasterIs (broadcaster->GetLLDBObjectPtr ());
+ }
+ return false;
+}
+
+bool
+SBEvent::BroadcasterMatchesRef (const SBBroadcaster &broadcaster)
+{
+ Event *lldb_event = SBEvent::GetLLDBObjectPtr();
+ if (lldb_event)
+ return lldb_event->BroadcasterIs (broadcaster.GetLLDBObjectPtr ());
+ return false;
+}
+
+void
+SBEvent::Clear()
+{
+ Event *lldb_event = SBEvent::GetLLDBObjectPtr();
+ if (lldb_event)
+ lldb_event->Clear();
+}
+
+EventSP &
+SBEvent::GetSharedPtr () const
+{
+ return m_event_sp;
+}
+
+Event *
+SBEvent::GetLLDBObjectPtr ()
+{
+ // 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_lldb_object...
+ if (m_event_sp)
+ m_lldb_object = m_event_sp.get();
+
+ return m_lldb_object;
+}
+
+const Event *
+SBEvent::GetLLDBObjectPtr () 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_lldb_object...
+ if (m_event_sp)
+ m_lldb_object = m_event_sp.get();
+
+ return m_lldb_object;
+}
+
+void
+SBEvent::SetEventSP (EventSP &event_sp)
+{
+ m_event_sp = event_sp;
+ m_lldb_object = m_event_sp.get();
+}
+
+void
+SBEvent::SetLLDBObjectPtr (Event* event_ptr)
+{
+ m_lldb_object = event_ptr;
+ m_event_sp.reset();
+}
+
+bool
+SBEvent::IsValid() const
+{
+ // Do NOT use m_lldb_object directly!!! Must use the SBEvent::GetLLDBObjectPtr()
+ // accessor. See comments in SBEvent::GetLLDBObjectPtr()....
+ return SBEvent::GetLLDBObjectPtr() != NULL;
+
+}
+
+const char *
+SBEvent::GetCStringFromEvent (const SBEvent &event)
+{
+ return reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event.GetLLDBObjectPtr()));
+}
+
+
diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp
new file mode 100644
index 00000000000..48c751177c0
--- /dev/null
+++ b/lldb/source/API/SBFileSpec.cpp
@@ -0,0 +1,133 @@
+//===-- 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 "lldb/API/SBFileSpec.h"
+#include "lldb/Core/FileSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+SBFileSpec::SBFileSpec () :
+ m_lldb_object_ap()
+{
+}
+
+SBFileSpec::SBFileSpec (const SBFileSpec &rhs) :
+ m_lldb_object_ap()
+{
+ if (rhs.m_lldb_object_ap.get())
+ m_lldb_object_ap.reset (new FileSpec (*m_lldb_object_ap));
+}
+
+SBFileSpec::SBFileSpec (const char *path) :
+ m_lldb_object_ap(new FileSpec (path))
+{
+}
+
+SBFileSpec::~SBFileSpec ()
+{
+}
+
+const SBFileSpec &
+SBFileSpec::operator = (const SBFileSpec &rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ m_lldb_object_ap.reset (new lldb_private::FileSpec(*rhs.m_lldb_object_ap.get()));
+ }
+ return *this;
+}
+
+bool
+SBFileSpec::IsValid() const
+{
+ return m_lldb_object_ap.get() != NULL;
+}
+
+bool
+SBFileSpec::Exists () const
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->Exists();
+ return false;
+}
+
+
+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
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->GetFilename().AsCString();
+ return NULL;
+}
+
+const char *
+SBFileSpec::GetDirectory() const
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->GetDirectory().AsCString();
+ return NULL;
+}
+
+uint32_t
+SBFileSpec::GetPath (char *dst_path, size_t dst_len) const
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->GetPath (dst_path, dst_len);
+
+ if (dst_path && dst_len)
+ *dst_path = '\0';
+ return 0;
+}
+
+
+const lldb_private::FileSpec *
+SBFileSpec::operator->() const
+{
+ return m_lldb_object_ap.get();
+}
+
+const lldb_private::FileSpec *
+SBFileSpec::get() const
+{
+ return m_lldb_object_ap.get();
+}
+
+
+const lldb_private::FileSpec &
+SBFileSpec::operator*() const
+{
+ return *m_lldb_object_ap.get();
+}
+
+const lldb_private::FileSpec &
+SBFileSpec::ref() const
+{
+ return *m_lldb_object_ap.get();
+}
+
+
+void
+SBFileSpec::SetFileSpec (const lldb_private::FileSpec& fs)
+{
+ if (m_lldb_object_ap.get())
+ *m_lldb_object_ap = fs;
+ else
+ m_lldb_object_ap.reset (new FileSpec (fs));
+}
+
diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp
new file mode 100644
index 00000000000..d513e5b726d
--- /dev/null
+++ b/lldb/source/API/SBFrame.cpp
@@ -0,0 +1,394 @@
+//===-- 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 "SBFrame.h"
+
+#include <string>
+#include <algorithm>
+
+#include "lldb/lldb-types.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Symbol/Block.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/Thread.h"
+
+#include "SBDebugger.h"
+#include "SBValue.h"
+#include "SBAddress.h"
+#include "SBSymbolContext.h"
+#include "SBThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBFrame::SBFrame () :
+ m_lldb_object_sp ()
+{
+}
+
+SBFrame::SBFrame (const lldb::StackFrameSP &lldb_object_sp) :
+ m_lldb_object_sp (lldb_object_sp)
+{
+}
+
+SBFrame::~SBFrame()
+{
+}
+
+
+void
+SBFrame::SetFrame (const lldb::StackFrameSP &lldb_object_sp)
+{
+ m_lldb_object_sp = lldb_object_sp;
+}
+
+
+bool
+SBFrame::IsValid() const
+{
+ return (m_lldb_object_sp.get() != NULL);
+}
+
+SBSymbolContext
+SBFrame::GetSymbolContext (uint32_t resolve_scope) const
+{
+ SBSymbolContext sb_sym_ctx;
+ if (m_lldb_object_sp)
+ sb_sym_ctx.SetSymbolContext(&m_lldb_object_sp->GetSymbolContext (resolve_scope));
+ return sb_sym_ctx;
+}
+
+SBModule
+SBFrame::GetModule () const
+{
+ SBModule sb_module (m_lldb_object_sp->GetSymbolContext (eSymbolContextModule).module_sp);
+ return sb_module;
+}
+
+SBCompileUnit
+SBFrame::GetCompileUnit () const
+{
+ SBCompileUnit sb_comp_unit(m_lldb_object_sp->GetSymbolContext (eSymbolContextCompUnit).comp_unit);
+ return sb_comp_unit;
+}
+
+SBFunction
+SBFrame::GetFunction () const
+{
+ SBFunction sb_function(m_lldb_object_sp->GetSymbolContext (eSymbolContextFunction).function);
+ return sb_function;
+}
+
+SBBlock
+SBFrame::GetBlock () const
+{
+ SBBlock sb_block(m_lldb_object_sp->GetSymbolContext (eSymbolContextBlock).block);
+ return sb_block;
+}
+
+SBLineEntry
+SBFrame::GetLineEntry () const
+{
+ SBLineEntry sb_line_entry(&m_lldb_object_sp->GetSymbolContext (eSymbolContextLineEntry).line_entry);
+ return sb_line_entry;
+}
+
+uint32_t
+SBFrame::GetFrameID () const
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetID();
+ else
+ return UINT32_MAX;
+}
+
+
+lldb::addr_t
+SBFrame::GetPC () const
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetPC().GetLoadAddress (&m_lldb_object_sp->GetThread().GetProcess());
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+SBFrame::SetPC (lldb::addr_t new_pc)
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetRegisterContext()->SetPC (new_pc);
+ return false;
+}
+
+lldb::addr_t
+SBFrame::GetSP () const
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetRegisterContext()->GetSP();
+ return LLDB_INVALID_ADDRESS;
+}
+
+
+lldb::addr_t
+SBFrame::GetFP () const
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetRegisterContext()->GetFP();
+ return LLDB_INVALID_ADDRESS;
+}
+
+
+SBAddress
+SBFrame::GetPCAddress () const
+{
+ SBAddress sb_addr;
+ if (m_lldb_object_sp)
+ sb_addr.SetAddress (&m_lldb_object_sp->GetPC());
+ return sb_addr;
+}
+
+void
+SBFrame::Clear()
+{
+ m_lldb_object_sp.reset();
+}
+
+SBValue
+SBFrame::LookupVar (const char *var_name)
+{
+ lldb::VariableSP var_sp;
+ if (IsValid ())
+ {
+ lldb_private::VariableList variable_list;
+ SBSymbolContext sc = GetSymbolContext (eSymbolContextEverything);
+
+ SBBlock block = sc.GetBlock();
+ if (block.IsValid())
+ block.AppendVariables (true, true, &variable_list);
+
+ const uint32_t num_variables = variable_list.GetSize();
+
+ bool found = false;
+ for (int i = 0; i < num_variables && !found; ++i)
+ {
+ var_sp = variable_list.GetVariableAtIndex(i);
+ if (var_sp
+ && (var_sp.get()->GetName() == lldb_private::ConstString(var_name)))
+ found = true;
+ }
+ if (!found)
+ var_sp.reset();
+ }
+ SBValue sb_value (ValueObjectSP (new ValueObjectVariable (var_sp)));
+ return sb_value;
+}
+
+SBValue
+SBFrame::LookupVarInScope (const char *var_name, const char *scope)
+{
+ lldb::VariableSP var_sp;
+ if (IsValid())
+ {
+ std::string scope_str = scope;
+ lldb::ValueType var_scope = eValueTypeInvalid;
+ // Convert scope_str to be all lowercase;
+ std::transform (scope_str.begin(), scope_str.end(), scope_str.begin(), ::tolower);
+
+ if (scope_str.compare ("global") == 0)
+ var_scope = eValueTypeVariableGlobal;
+ else if (scope_str.compare ("local") == 0)
+ var_scope = eValueTypeVariableLocal;
+ else if (scope_str.compare ("parameter") == 0)
+ var_scope = eValueTypeVariableArgument;
+
+ if (var_scope != eValueTypeInvalid)
+ {
+ lldb_private::VariableList variable_list;
+ SBSymbolContext sc = GetSymbolContext (eSymbolContextEverything);
+
+ SBBlock block = sc.GetBlock();
+ if (block.IsValid())
+ block.AppendVariables (true, true, &variable_list);
+
+ const uint32_t num_variables = variable_list.GetSize();
+
+ bool found = false;
+ for (int i = 0; i < num_variables && !found; ++i)
+ {
+ var_sp = variable_list.GetVariableAtIndex(i);
+ if (var_sp
+ && (var_sp.get()->GetName() == lldb_private::ConstString(var_name))
+ && var_sp.get()->GetScope() == var_scope)
+ found = true;
+ }
+ if (!found)
+ var_sp.reset();
+ }
+ }
+ SBValue sb_value (ValueObjectSP (new ValueObjectVariable (var_sp)));
+ return sb_value;
+}
+
+bool
+SBFrame::operator == (const SBFrame &rhs) const
+{
+ return m_lldb_object_sp.get() == rhs.m_lldb_object_sp.get();
+}
+
+bool
+SBFrame::operator != (const SBFrame &rhs) const
+{
+ return m_lldb_object_sp.get() != rhs.m_lldb_object_sp.get();
+}
+
+lldb_private::StackFrame *
+SBFrame::operator->() const
+{
+ return m_lldb_object_sp.get();
+}
+
+lldb_private::StackFrame *
+SBFrame::get() const
+{
+ return m_lldb_object_sp.get();
+}
+
+
+SBThread
+SBFrame::GetThread () const
+{
+ SBThread sb_thread (m_lldb_object_sp->GetThread().GetSP());
+ return sb_thread;
+}
+
+const char *
+SBFrame::Disassemble () const
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->Disassemble();
+ return NULL;
+}
+
+
+
+lldb_private::StackFrame *
+SBFrame::GetLLDBObjectPtr ()
+{
+ return m_lldb_object_sp.get();
+}
+
+SBValueList
+SBFrame::GetVariables (bool arguments,
+ bool locals,
+ bool statics,
+ bool in_scope_only)
+{
+ SBValueList value_list;
+ if (m_lldb_object_sp)
+ {
+ size_t i;
+ VariableList *variable_list = m_lldb_object_sp->GetVariableList();
+ 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;
+ }
+ if (add_variable)
+ {
+ if (in_scope_only && !variable_sp->IsInScope(m_lldb_object_sp.get()))
+ continue;
+
+ value_list.Append(ValueObjectSP (new ValueObjectVariable (variable_sp)));
+ }
+ }
+ }
+ }
+ }
+
+ if (statics)
+ {
+ CompileUnit *frame_comp_unit = m_lldb_object_sp->GetSymbolContext (eSymbolContextCompUnit).comp_unit;
+
+ if (frame_comp_unit)
+ {
+ variable_list = frame_comp_unit->GetVariableList(true).get();
+
+ 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)
+ {
+ value_list.Append(ValueObjectSP (new ValueObjectVariable (variable_sp)));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return value_list;
+}
+
+lldb::SBValueList
+SBFrame::GetRegisters ()
+{
+ SBValueList value_list;
+ if (m_lldb_object_sp)
+ {
+ RegisterContext *reg_ctx = m_lldb_object_sp->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(ValueObjectSP (new ValueObjectRegisterSet (reg_ctx, set_idx)));
+ }
+ }
+ }
+ return value_list;
+}
+
diff --git a/lldb/source/API/SBFunction.cpp b/lldb/source/API/SBFunction.cpp
new file mode 100644
index 00000000000..010a5ec17df
--- /dev/null
+++ b/lldb/source/API/SBFunction.cpp
@@ -0,0 +1,64 @@
+//===-- 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/Symbol/Function.h"
+
+using namespace lldb;
+
+
+SBFunction::SBFunction () :
+ m_lldb_object_ptr (NULL)
+{
+}
+
+SBFunction::SBFunction (lldb_private::Function *lldb_object_ptr) :
+ m_lldb_object_ptr (lldb_object_ptr)
+{
+}
+
+SBFunction::~SBFunction ()
+{
+ m_lldb_object_ptr = NULL;
+}
+
+bool
+SBFunction::IsValid () const
+{
+ return m_lldb_object_ptr != NULL;
+}
+
+const char *
+SBFunction::GetName() const
+{
+ if (m_lldb_object_ptr)
+ return m_lldb_object_ptr->GetMangled().GetName().AsCString();
+ return NULL;
+}
+
+const char *
+SBFunction::GetMangledName () const
+{
+ if (m_lldb_object_ptr)
+ return m_lldb_object_ptr->GetMangled().GetMangledName().AsCString();
+ return NULL;
+}
+
+bool
+SBFunction::operator == (const SBFunction &rhs) const
+{
+ return m_lldb_object_ptr == rhs.m_lldb_object_ptr;
+}
+
+bool
+SBFunction::operator != (const SBFunction &rhs) const
+{
+ return m_lldb_object_ptr != rhs.m_lldb_object_ptr;
+}
diff --git a/lldb/source/API/SBHostOS.cpp b/lldb/source/API/SBHostOS.cpp
new file mode 100644
index 00000000000..f0af9cd5069
--- /dev/null
+++ b/lldb/source/API/SBHostOS.cpp
@@ -0,0 +1,64 @@
+//===-- 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/Core/FileSpec.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;
+}
+
+lldb::thread_t
+SBHostOS::ThreadCreate
+(
+ const char *name,
+ void *(*thread_function)(void *),
+ void *thread_arg,
+ SBError *error_ptr
+)
+{
+ 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/lldb/source/API/SBInputReader.cpp b/lldb/source/API/SBInputReader.cpp
new file mode 100644
index 00000000000..022d73207ad
--- /dev/null
+++ b/lldb/source/API/SBInputReader.cpp
@@ -0,0 +1,169 @@
+//===-- 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/SBInputReader.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBStringList.h"
+#include "lldb/Core/InputReader.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBInputReader::SBInputReader () :
+ m_reader_sp (),
+ m_callback_function (NULL),
+ m_callback_baton (NULL)
+
+{
+}
+
+SBInputReader::SBInputReader (const lldb::InputReaderSP &reader_sp) :
+ m_reader_sp (reader_sp)
+{
+}
+
+SBInputReader::SBInputReader (const SBInputReader &rhs) :
+ m_reader_sp (rhs.m_reader_sp)
+{
+}
+
+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
+(
+ Callback callback_function,
+ void *callback_baton,
+ lldb::InputReaderGranularity granularity,
+ const char *end_token,
+ const char *prompt,
+ bool echo
+)
+{
+ SBError sb_error;
+ m_reader_sp.reset (new InputReader ());
+
+ m_callback_function = callback_function;
+ m_callback_baton = callback_baton;
+
+ if (m_reader_sp)
+ {
+ sb_error.SetError (m_reader_sp->Initialize (SBInputReader::PrivateCallback,
+ this,
+ granularity,
+ end_token,
+ prompt,
+ echo));
+ }
+
+ if (sb_error.Fail())
+ {
+ m_reader_sp.reset ();
+ m_callback_function = NULL;
+ m_callback_baton = NULL;
+ }
+
+ return sb_error;
+}
+
+bool
+SBInputReader::IsValid () const
+{
+ return (m_reader_sp.get() != NULL);
+}
+
+const SBInputReader &
+SBInputReader::operator = (const SBInputReader &rhs)
+{
+ if (this != &rhs)
+ m_reader_sp = rhs.m_reader_sp;
+ return *this;
+}
+
+lldb_private::InputReader *
+SBInputReader::operator->() const
+{
+ return m_reader_sp.get();
+}
+
+lldb::InputReaderSP &
+SBInputReader::operator *()
+{
+ return m_reader_sp;
+}
+
+const lldb::InputReaderSP &
+SBInputReader::operator *() const
+{
+ return m_reader_sp;
+}
+
+lldb_private::InputReader *
+SBInputReader::get() const
+{
+ return m_reader_sp.get();
+}
+
+bool
+SBInputReader::IsDone () const
+{
+ if (m_reader_sp)
+ return m_reader_sp->IsDone();
+ else
+ return true;
+}
+
+void
+SBInputReader::SetIsDone (bool value)
+{
+ if (m_reader_sp)
+ m_reader_sp->SetIsDone (value);
+}
+
+bool
+SBInputReader::IsActive () const
+{
+ if (m_reader_sp)
+ return m_reader_sp->IsActive();
+ else
+ return false;
+}
+
+InputReaderGranularity
+SBInputReader::GetGranularity ()
+{
+ if (m_reader_sp)
+ return m_reader_sp->GetGranularity();
+ else
+ return eInputReaderGranularityInvalid;
+}
diff --git a/lldb/source/API/SBInstruction.cpp b/lldb/source/API/SBInstruction.cpp
new file mode 100644
index 00000000000..564fda0b8cb
--- /dev/null
+++ b/lldb/source/API/SBInstruction.cpp
@@ -0,0 +1,74 @@
+//===-- 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/Core/Disassembler.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//SBInstruction::SBInstruction (lldb_private::Disassembler::Instruction *lldb_insn) :
+// m_lldb_object_sp (lldb_insn);
+//{
+//}
+
+SBInstruction::SBInstruction ()
+{
+}
+
+SBInstruction::~SBInstruction ()
+{
+}
+
+//bool
+//SBInstruction::IsValid()
+//{
+// return (m_lldb_object_sp.get() != NULL);
+//}
+
+//size_t
+//SBInstruction::GetByteSize ()
+//{
+// if (IsValid())
+// {
+// return m_lldb_object_sp->GetByteSize();
+// }
+// return 0;
+//}
+
+//void
+//SBInstruction::SetByteSize (size_T byte_size)
+//{
+// if (IsValid ())
+// {
+// m_lldb_object_sp->SetByteSize (byte_size);
+// }
+//}
+
+//bool
+//SBInstruction::DoesBranch ()
+//{
+// if (IsValid ())
+// {
+// return m_lldb_object_sp->DoesBranch ();
+// }
+// return false;
+//}
+
+void
+SBInstruction::Print (FILE *out)
+{
+ if (out == NULL)
+ return;
+
+ //StreamFile out_strem (out);
+
+ //m_lldb_object_sp->Dump (out, LLDB_INVALID_ADDRESS, NULL, 0);
+}
diff --git a/lldb/source/API/SBInstructionList.cpp b/lldb/source/API/SBInstructionList.cpp
new file mode 100644
index 00000000000..d34e9d100a9
--- /dev/null
+++ b/lldb/source/API/SBInstructionList.cpp
@@ -0,0 +1,53 @@
+//===-- 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"
+
+using namespace lldb;
+
+
+SBInstructionList::SBInstructionList ()
+{
+}
+
+SBInstructionList::~SBInstructionList ()
+{
+}
+
+size_t
+SBInstructionList::GetSize ()
+{
+ return 0;
+}
+
+SBInstruction
+SBInstructionList::GetInstructionAtIndex (uint32_t idx)
+{
+ SBInstruction inst;
+ return inst;
+}
+
+void
+SBInstructionList::Clear ()
+{
+}
+
+void
+SBInstructionList::AppendInstruction (SBInstruction insn)
+{
+}
+
+void
+SBInstructionList::Print (FILE *out)
+{
+ if (out == NULL)
+ return;
+}
+
diff --git a/lldb/source/API/SBLineEntry.cpp b/lldb/source/API/SBLineEntry.cpp
new file mode 100644
index 00000000000..483540050a3
--- /dev/null
+++ b/lldb/source/API/SBLineEntry.cpp
@@ -0,0 +1,158 @@
+//===-- 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 "lldb/API/SBLineEntry.h"
+#include "lldb/Symbol/LineEntry.h"
+
+using namespace lldb;
+
+
+SBLineEntry::SBLineEntry () :
+ m_lldb_object_ap ()
+{
+}
+
+SBLineEntry::SBLineEntry (const SBLineEntry &rhs) :
+ m_lldb_object_ap ()
+{
+ if (rhs.IsValid())
+ {
+ m_lldb_object_ap.reset (new lldb_private::LineEntry (*rhs));
+ }
+}
+
+
+
+SBLineEntry::SBLineEntry (const lldb_private::LineEntry *lldb_object_ptr) :
+ m_lldb_object_ap ()
+{
+ if (lldb_object_ptr)
+ m_lldb_object_ap.reset (new lldb_private::LineEntry(*lldb_object_ptr));
+}
+
+const SBLineEntry &
+SBLineEntry::operator = (const SBLineEntry &rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ m_lldb_object_ap.reset (new lldb_private::LineEntry(*rhs));
+ }
+ return *this;
+}
+
+void
+SBLineEntry::SetLineEntry (const lldb_private::LineEntry &lldb_object_ref)
+{
+ if (m_lldb_object_ap.get())
+ (*m_lldb_object_ap.get()) = lldb_object_ref;
+ else
+ m_lldb_object_ap.reset (new lldb_private::LineEntry (lldb_object_ref));
+}
+
+
+SBLineEntry::~SBLineEntry ()
+{
+}
+
+
+SBAddress
+SBLineEntry::GetStartAddress () const
+{
+ SBAddress sb_address;
+ if (m_lldb_object_ap.get())
+ sb_address.SetAddress(&m_lldb_object_ap->range.GetBaseAddress());
+ return sb_address;
+}
+
+SBAddress
+SBLineEntry::GetEndAddress () const
+{
+ SBAddress sb_address;
+ if (m_lldb_object_ap.get())
+ {
+ sb_address.SetAddress(&m_lldb_object_ap->range.GetBaseAddress());
+ sb_address.OffsetAddress(m_lldb_object_ap->range.GetByteSize());
+ }
+ return sb_address;
+}
+
+bool
+SBLineEntry::IsValid () const
+{
+ return m_lldb_object_ap.get() != NULL;
+}
+
+
+SBFileSpec
+SBLineEntry::GetFileSpec () const
+{
+ SBFileSpec sb_file_spec;
+ if (m_lldb_object_ap.get() && m_lldb_object_ap->file)
+ sb_file_spec.SetFileSpec(m_lldb_object_ap->file);
+ return sb_file_spec;
+}
+
+uint32_t
+SBLineEntry::GetLine () const
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->line;
+ return 0;
+}
+
+
+uint32_t
+SBLineEntry::GetColumn () const
+{
+ if (m_lldb_object_ap.get())
+ return m_lldb_object_ap->column;
+ return 0;
+}
+
+bool
+SBLineEntry::operator == (const SBLineEntry &rhs) const
+{
+ lldb_private::LineEntry *lhs_ptr = m_lldb_object_ap.get();
+ lldb_private::LineEntry *rhs_ptr = rhs.m_lldb_object_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_lldb_object_ap.get();
+ lldb_private::LineEntry *rhs_ptr = rhs.m_lldb_object_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_lldb_object_ap.get();
+}
+
+const lldb_private::LineEntry &
+SBLineEntry::operator*() const
+{
+ return *m_lldb_object_ap;
+}
+
+
+
+
+
diff --git a/lldb/source/API/SBListener.cpp b/lldb/source/API/SBListener.cpp
new file mode 100644
index 00000000000..6f2cf7bc911
--- /dev/null
+++ b/lldb/source/API/SBListener.cpp
@@ -0,0 +1,299 @@
+//===-- 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/Core/Listener.h"
+#include "lldb/lldb-forward-rtti.h"
+#include "lldb/Host/TimeValue.h"
+
+#include "SBListener.h"
+#include "SBEvent.h"
+#include "SBBroadcaster.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBListener::SBListener ()
+{
+}
+
+SBListener::SBListener (const char *name) :
+ m_lldb_object_ptr (new Listener (name)),
+ m_lldb_object_ptr_owned (true)
+{
+}
+
+SBListener::SBListener (Listener &listener) :
+ m_lldb_object_ptr (&listener),
+ m_lldb_object_ptr_owned (false)
+{
+}
+
+SBListener::~SBListener ()
+{
+ if (m_lldb_object_ptr_owned)
+ {
+ if (m_lldb_object_ptr)
+ {
+ delete m_lldb_object_ptr;
+ m_lldb_object_ptr = NULL;
+ }
+ }
+}
+
+bool
+SBListener::IsValid() const
+{
+ return m_lldb_object_ptr != NULL;
+}
+
+void
+SBListener::AddEvent (const SBEvent &event)
+{
+ EventSP &event_sp = event.GetSharedPtr ();
+ if (event_sp)
+ m_lldb_object_ptr->AddEvent (event_sp);
+}
+
+void
+SBListener::Clear ()
+{
+ if (IsValid())
+ m_lldb_object_ptr->Clear ();
+}
+
+uint32_t
+SBListener::StartListeningForEvents (const SBBroadcaster& broadcaster, uint32_t event_mask)
+{
+ if (IsValid() && broadcaster.IsValid())
+ {
+ return m_lldb_object_ptr->StartListeningForEvents (broadcaster.GetLLDBObjectPtr (), event_mask);
+ }
+ return false;
+}
+
+bool
+SBListener::StopListeningForEvents (const SBBroadcaster& broadcaster, uint32_t event_mask)
+{
+ if (IsValid() && broadcaster.IsValid())
+ {
+ return m_lldb_object_ptr->StopListeningForEvents (broadcaster.GetLLDBObjectPtr (), event_mask);
+ }
+ return false;
+}
+
+bool
+SBListener::WaitForEvent (uint32_t num_seconds, SBEvent &event)
+{
+ if (IsValid())
+ {
+ TimeValue time_value;
+ if (num_seconds != UINT32_MAX)
+ {
+ assert (num_seconds != 0); // Take this out after all calls with timeout set to zero have been removed....
+ time_value = TimeValue::Now();
+ time_value.OffsetWithSeconds (num_seconds);
+ }
+ EventSP event_sp;
+ if (m_lldb_object_ptr->WaitForEvent (time_value.IsValid() ? &time_value : NULL, event_sp))
+ {
+ event.SetEventSP (event_sp);
+ return true;
+ }
+ }
+ event.SetLLDBObjectPtr (NULL);
+ return false;
+}
+
+bool
+SBListener::WaitForEventForBroadcaster
+(
+ uint32_t num_seconds,
+ const SBBroadcaster &broadcaster,
+ SBEvent &event
+)
+{
+ if (IsValid() && broadcaster.IsValid())
+ {
+ TimeValue time_value;
+ if (num_seconds != UINT32_MAX)
+ {
+ time_value = TimeValue::Now();
+ time_value.OffsetWithSeconds (num_seconds);
+ }
+ EventSP event_sp;
+ if (m_lldb_object_ptr->WaitForEventForBroadcaster (time_value.IsValid() ? &time_value : NULL,
+ broadcaster.GetLLDBObjectPtr (),
+ event_sp))
+ {
+ event.SetEventSP (event_sp);
+ return true;
+ }
+
+ }
+ event.SetLLDBObjectPtr (NULL);
+ return false;
+}
+
+bool
+SBListener::WaitForEventForBroadcasterWithType
+(
+ uint32_t num_seconds,
+ const SBBroadcaster &broadcaster,
+ uint32_t event_type_mask,
+ SBEvent &event
+)
+{
+ if (IsValid() && broadcaster.IsValid())
+ {
+ TimeValue time_value;
+ if (num_seconds != UINT32_MAX)
+ {
+ time_value = TimeValue::Now();
+ time_value.OffsetWithSeconds (num_seconds);
+ }
+ EventSP event_sp;
+ if (m_lldb_object_ptr->WaitForEventForBroadcasterWithType (time_value.IsValid() ? &time_value : NULL,
+ broadcaster.GetLLDBObjectPtr (),
+ event_type_mask,
+ event_sp))
+ {
+ event.SetEventSP (event_sp);
+ return true;
+ }
+ }
+ event.SetLLDBObjectPtr (NULL);
+ return false;
+}
+
+bool
+SBListener::PeekAtNextEvent (SBEvent &event)
+{
+ if (m_lldb_object_ptr)
+ {
+ event.SetLLDBObjectPtr (m_lldb_object_ptr->PeekAtNextEvent ());
+ return event.IsValid();
+ }
+ event.SetLLDBObjectPtr (NULL);
+ return false;
+}
+
+bool
+SBListener::PeekAtNextEventForBroadcaster (const SBBroadcaster &broadcaster, SBEvent &event)
+{
+ if (IsValid() && broadcaster.IsValid())
+ {
+ event.SetLLDBObjectPtr (m_lldb_object_ptr->PeekAtNextEventForBroadcaster (broadcaster.GetLLDBObjectPtr ()));
+ return event.IsValid();
+ }
+ event.SetLLDBObjectPtr (NULL);
+ return false;
+}
+
+bool
+SBListener::PeekAtNextEventForBroadcasterWithType (const SBBroadcaster &broadcaster, uint32_t event_type_mask,
+ SBEvent &event)
+{
+ if (IsValid() && broadcaster.IsValid())
+ {
+ event.SetLLDBObjectPtr(m_lldb_object_ptr->PeekAtNextEventForBroadcasterWithType (broadcaster.GetLLDBObjectPtr (), event_type_mask));
+ return event.IsValid();
+ }
+ event.SetLLDBObjectPtr (NULL);
+ return false;
+}
+
+bool
+SBListener::GetNextEvent (SBEvent &event)
+{
+ if (m_lldb_object_ptr)
+ {
+ EventSP event_sp;
+ if (m_lldb_object_ptr->GetNextEvent (event_sp))
+ {
+ event.SetEventSP (event_sp);
+ return true;
+ }
+ }
+ event.SetLLDBObjectPtr (NULL);
+ return false;
+}
+
+bool
+SBListener::GetNextEventForBroadcaster (const SBBroadcaster &broadcaster, SBEvent &event)
+{
+ if (IsValid() && broadcaster.IsValid())
+ {
+ EventSP event_sp;
+ if (m_lldb_object_ptr->GetNextEventForBroadcaster (broadcaster.GetLLDBObjectPtr (), event_sp))
+ {
+ event.SetEventSP (event_sp);
+ return true;
+ }
+ }
+ event.SetLLDBObjectPtr (NULL);
+ return false;
+}
+
+bool
+SBListener::GetNextEventForBroadcasterWithType
+(
+ const SBBroadcaster &broadcaster,
+ uint32_t event_type_mask,
+ SBEvent &event
+)
+{
+ if (IsValid() && broadcaster.IsValid())
+ {
+ EventSP event_sp;
+ if (m_lldb_object_ptr->GetNextEventForBroadcasterWithType (broadcaster.GetLLDBObjectPtr (),
+ event_type_mask,
+ event_sp))
+ {
+ event.SetEventSP (event_sp);
+ return true;
+ }
+ }
+ event.SetLLDBObjectPtr (NULL);
+ return false;
+}
+
+bool
+SBListener::HandleBroadcastEvent (const SBEvent &event)
+{
+ if (m_lldb_object_ptr)
+ return m_lldb_object_ptr->HandleBroadcastEvent (event.GetSharedPtr());
+ return false;
+}
+
+lldb_private::Listener *
+SBListener::operator->() const
+{
+ return m_lldb_object_ptr;
+}
+
+lldb_private::Listener *
+SBListener::get() const
+{
+ return m_lldb_object_ptr;
+}
+
+lldb_private::Listener &
+SBListener::operator *()
+{
+ return *m_lldb_object_ptr;
+}
+
+const lldb_private::Listener &
+SBListener::operator *() const
+{
+ return *m_lldb_object_ptr;
+}
+
+
diff --git a/lldb/source/API/SBModule.cpp b/lldb/source/API/SBModule.cpp
new file mode 100644
index 00000000000..6a54c2177bf
--- /dev/null
+++ b/lldb/source/API/SBModule.cpp
@@ -0,0 +1,107 @@
+//===-- 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/SBFileSpec.h"
+#include "lldb/Core/Module.h"
+
+using namespace lldb;
+
+
+SBModule::SBModule () :
+ m_lldb_object_sp ()
+{
+}
+
+SBModule::SBModule (const lldb::ModuleSP& module_sp) :
+ m_lldb_object_sp (module_sp)
+{
+}
+
+SBModule::~SBModule ()
+{
+}
+
+bool
+SBModule::IsValid () const
+{
+ return m_lldb_object_sp.get() != NULL;
+}
+
+SBFileSpec
+SBModule::GetFileSpec () const
+{
+ SBFileSpec file_spec;
+ if (m_lldb_object_sp)
+ file_spec.SetFileSpec(m_lldb_object_sp->GetFileSpec());
+ return file_spec;
+}
+
+const uint8_t *
+SBModule::GetUUIDBytes () const
+{
+ if (m_lldb_object_sp)
+ return (const uint8_t *)m_lldb_object_sp->GetUUID().GetBytes();
+ return NULL;
+}
+
+
+bool
+SBModule::operator == (const SBModule &rhs) const
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp.get() == rhs.m_lldb_object_sp.get();
+ return false;
+}
+
+bool
+SBModule::operator != (const SBModule &rhs) const
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp.get() != rhs.m_lldb_object_sp.get();
+ return false;
+}
+
+lldb::ModuleSP &
+SBModule::operator *()
+{
+ return m_lldb_object_sp;
+}
+
+lldb_private::Module *
+SBModule::operator ->()
+{
+ return m_lldb_object_sp.get();
+}
+
+const lldb_private::Module *
+SBModule::operator ->() const
+{
+ return m_lldb_object_sp.get();
+}
+
+lldb_private::Module *
+SBModule::get()
+{
+ return m_lldb_object_sp.get();
+}
+
+const lldb_private::Module *
+SBModule::get() const
+{
+ return m_lldb_object_sp.get();
+}
+
+
+void
+SBModule::SetModule (const lldb::ModuleSP& module_sp)
+{
+ m_lldb_object_sp = module_sp;
+}
+
diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
new file mode 100644
index 00000000000..776939c9ea6
--- /dev/null
+++ b/lldb/source/API/SBProcess.cpp
@@ -0,0 +1,604 @@
+//===-- 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 "SBProcess.h"
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+#include "lldb/Core/Args.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+
+// Project includes
+
+#include "SBBroadcaster.h"
+#include "SBDebugger.h"
+#include "SBCommandReturnObject.h"
+#include "SBEvent.h"
+#include "SBThread.h"
+#include "SBStringList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+SBProcess::SBProcess () :
+ m_lldb_object_sp()
+{
+}
+
+
+//----------------------------------------------------------------------
+// SBProcess constructor
+//----------------------------------------------------------------------
+
+SBProcess::SBProcess (const SBProcess& rhs) :
+ m_lldb_object_sp (rhs.m_lldb_object_sp)
+{
+}
+
+
+SBProcess::SBProcess (const lldb::ProcessSP &process_sp) :
+ m_lldb_object_sp (process_sp)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SBProcess::~SBProcess()
+{
+}
+
+void
+SBProcess::SetProcess (const ProcessSP &process_sp)
+{
+ m_lldb_object_sp = process_sp;
+}
+
+void
+SBProcess::Clear ()
+{
+ m_lldb_object_sp.reset();
+}
+
+
+bool
+SBProcess::IsValid() const
+{
+ return m_lldb_object_sp.get() != NULL;
+}
+
+
+uint32_t
+SBProcess::GetNumThreads ()
+{
+ if (m_lldb_object_sp)
+ {
+ const bool can_update = true;
+ return m_lldb_object_sp->GetThreadList().GetSize(can_update);
+ }
+ return 0;
+}
+
+SBThread
+SBProcess::GetCurrentThread () const
+{
+ SBThread sb_thread;
+ if (m_lldb_object_sp)
+ sb_thread.SetThread (m_lldb_object_sp->GetThreadList().GetCurrentThread());
+ return sb_thread;
+}
+
+SBTarget
+SBProcess::GetTarget() const
+{
+ SBTarget sb_target;
+ if (m_lldb_object_sp)
+ sb_target = SBDebugger::FindTargetWithLLDBProcess (m_lldb_object_sp);
+ return sb_target;
+}
+
+
+size_t
+SBProcess::PutSTDIN (const char *src, size_t src_len)
+{
+ if (m_lldb_object_sp != NULL)
+ {
+ Error error;
+ return m_lldb_object_sp->PutSTDIN (src, src_len, error);
+ }
+ else
+ return 0;
+}
+
+size_t
+SBProcess::GetSTDOUT (char *dst, size_t dst_len) const
+{
+ if (m_lldb_object_sp != NULL)
+ {
+ Error error;
+ return m_lldb_object_sp->GetSTDOUT (dst, dst_len, error);
+ }
+ else
+ return 0;
+}
+
+size_t
+SBProcess::GetSTDERR (char *dst, size_t dst_len) const
+{
+ if (m_lldb_object_sp != NULL)
+ {
+ Error error;
+ return m_lldb_object_sp->GetSTDERR (dst, dst_len, error);
+ }
+ else
+ return 0;
+}
+
+void
+SBProcess::ReportCurrentState (const SBEvent &event, FILE *out) const
+{
+ if (out == NULL)
+ return;
+
+ if (m_lldb_object_sp != NULL)
+ {
+ const StateType event_state = SBProcess::GetStateFromEvent (event);
+ char message[1024];
+ int message_len = ::snprintf (message,
+ sizeof (message),
+ "Process %d %s\n",
+ m_lldb_object_sp->GetID(),
+ SBDebugger::StateAsCString (event_state));
+
+ if (message_len > 0)
+ ::fwrite (message, 1, message_len, out);
+ }
+}
+
+void
+SBProcess::AppendCurrentStateReport (const SBEvent &event, SBCommandReturnObject &result)
+{
+ if (m_lldb_object_sp != NULL)
+ {
+ const StateType event_state = SBProcess::GetStateFromEvent (event);
+ char message[1024];
+ ::snprintf (message,
+ sizeof (message),
+ "Process %d %s\n",
+ m_lldb_object_sp->GetID(),
+ SBDebugger::StateAsCString (event_state));
+
+ result.AppendMessage (message);
+ }
+}
+
+bool
+SBProcess::SetCurrentThread (const SBThread &thread)
+{
+ if (m_lldb_object_sp != NULL)
+ return m_lldb_object_sp->GetThreadList().SetCurrentThreadByID (thread.GetThreadID());
+ return false;
+}
+
+bool
+SBProcess::SetCurrentThreadByID (uint32_t tid)
+{
+ if (m_lldb_object_sp != NULL)
+ return m_lldb_object_sp->GetThreadList().SetCurrentThreadByID (tid);
+ return false;
+}
+
+SBThread
+SBProcess::GetThreadAtIndex (size_t index)
+{
+ SBThread thread;
+ if (m_lldb_object_sp)
+ thread.SetThread (m_lldb_object_sp->GetThreadList().GetThreadAtIndex(index));
+ return thread;
+}
+
+StateType
+SBProcess::GetState ()
+{
+ if (m_lldb_object_sp != NULL)
+ return m_lldb_object_sp->GetState();
+ else
+ return eStateInvalid;
+}
+
+
+int
+SBProcess::GetExitStatus ()
+{
+ if (m_lldb_object_sp != NULL)
+ return m_lldb_object_sp->GetExitStatus ();
+ else
+ return 0;
+}
+
+const char *
+SBProcess::GetExitDescription ()
+{
+ if (m_lldb_object_sp != NULL)
+ return m_lldb_object_sp->GetExitDescription ();
+ else
+ return NULL;
+}
+
+lldb::pid_t
+SBProcess::GetProcessID ()
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetID();
+ else
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+uint32_t
+SBProcess::GetAddressByteSize () const
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetAddressByteSize();
+ else
+ return 0;
+}
+
+
+void
+SBProcess::DisplayThreadsInfo (FILE *out, FILE *err, bool only_threads_with_stop_reason)
+{
+ if (m_lldb_object_sp != NULL)
+ {
+ size_t num_thread_infos_dumped = 0;
+ size_t num_threads = GetNumThreads();
+
+ if (out == NULL)
+ out = SBDebugger::GetOutputFileHandle();
+
+ if (err == NULL)
+ err = SBDebugger::GetErrorFileHandle();
+
+ if ((out == NULL) ||(err == NULL))
+ return;
+
+ if (num_threads > 0)
+ {
+ Thread::StopInfo thread_stop_info;
+ SBThread curr_thread (m_lldb_object_sp->GetThreadList().GetCurrentThread());
+ for (int i = 0; i < num_threads; ++i)
+ {
+ SBThread thread (m_lldb_object_sp->GetThreadList().GetThreadAtIndex(i));
+ if (thread.IsValid())
+ {
+ bool is_current_thread = false;
+ StreamFile str (out);
+ if (thread == curr_thread)
+ is_current_thread = true;
+ StopReason thread_stop_reason = eStopReasonNone;
+ if (thread->GetStopInfo (&thread_stop_info))
+ {
+ thread_stop_reason = thread_stop_info.GetStopReason();
+ if (thread_stop_reason == eStopReasonNone)
+ {
+ if (only_threads_with_stop_reason && !is_current_thread)
+ continue;
+ }
+ }
+ ++num_thread_infos_dumped;
+ fprintf (out, " %c thread #%u: tid = 0x%4.4x, pc = 0x%16.16llx",
+ (is_current_thread ? '*' : ' '),
+ thread->GetIndexID(), thread->GetID(), thread->GetRegisterContext()->GetPC());
+
+ StackFrameSP frame_sp(thread->GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ SymbolContext sc (frame_sp->GetSymbolContext (eSymbolContextEverything));
+ fprintf (out, ", where = ");
+ sc.DumpStopContext (&str, m_lldb_object_sp.get(), frame_sp->GetPC ());
+ }
+
+ if (thread_stop_reason != eStopReasonNone)
+ {
+ fprintf (out, ", stop reason = ");
+ thread_stop_info.Dump (&str);
+ }
+
+ const char *thread_name = thread->GetName();
+ if (thread_name && thread_name[0])
+ fprintf (out, ", thread_name = '%s'", thread_name);
+
+ fprintf (out, "\n");
+
+ SBThread sb_thread (thread);
+ sb_thread.DisplayFramesForCurrentContext (out, err, 0, 1, false, 1);
+ }
+ }
+ }
+ }
+}
+bool
+SBProcess::WaitUntilProcessHasStopped (SBCommandReturnObject &result)
+{
+ bool state_changed = false;
+
+ if (IsValid())
+ {
+ EventSP event_sp;
+ StateType state = m_lldb_object_sp->WaitForStateChangedEvents (NULL, event_sp);
+
+ while (StateIsStoppedState (state))
+ {
+ state = m_lldb_object_sp->WaitForStateChangedEvents (NULL, event_sp);
+ SBEvent event (event_sp);
+ AppendCurrentStateReport (event, result);
+ state_changed = true;
+ }
+ }
+ return state_changed;
+}
+
+SBError
+SBProcess::Continue ()
+{
+ SBError sb_error;
+ if (IsValid())
+ sb_error.SetError(m_lldb_object_sp->Resume());
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+
+ return sb_error;
+}
+
+
+SBError
+SBProcess::Destroy ()
+{
+ SBError sb_error;
+ if (m_lldb_object_sp)
+ sb_error.SetError(m_lldb_object_sp->Destroy());
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+
+ return sb_error;
+}
+
+
+SBError
+SBProcess::Stop ()
+{
+ SBError sb_error;
+ if (IsValid())
+ sb_error.SetError (m_lldb_object_sp->Halt());
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+ return sb_error;
+}
+
+SBError
+SBProcess::Kill ()
+{
+ SBError sb_error;
+ if (m_lldb_object_sp)
+ sb_error.SetError (m_lldb_object_sp->Destroy());
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+ return sb_error;
+}
+
+
+SBError
+SBProcess::AttachByName (const char *name, bool wait_for_launch)
+{
+ SBError sb_error;
+ if (m_lldb_object_sp)
+ sb_error.SetError (m_lldb_object_sp->Attach (name, wait_for_launch));
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+ return sb_error;
+}
+
+lldb::pid_t
+SBProcess::AttachByPID (lldb::pid_t attach_pid) // DEPRECATED: will be removed in a few builds in favor of SBError AttachByPID(pid_t)
+{
+ Attach (attach_pid);
+ return GetProcessID();
+}
+
+
+SBError
+SBProcess::Attach (lldb::pid_t attach_pid)
+{
+ SBError sb_error;
+ if (m_lldb_object_sp)
+ sb_error.SetError (m_lldb_object_sp->Attach (attach_pid));
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+ return sb_error;
+}
+
+SBError
+SBProcess::Detach ()
+{
+ SBError sb_error;
+ if (m_lldb_object_sp)
+ sb_error.SetError (m_lldb_object_sp->Detach());
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+
+ return sb_error;
+}
+
+SBError
+SBProcess::Signal (int signal)
+{
+ SBError sb_error;
+ if (m_lldb_object_sp)
+ sb_error.SetError (m_lldb_object_sp->Signal (signal));
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+ return sb_error;
+}
+
+void
+SBProcess::ListThreads ()
+{
+ FILE *out = SBDebugger::GetOutputFileHandle();
+ if (out == NULL)
+ return;
+
+ if (m_lldb_object_sp)
+ {
+ size_t num_threads = GetNumThreads ();
+ if (num_threads > 0)
+ {
+ Thread *cur_thread = m_lldb_object_sp->GetThreadList().GetCurrentThread().get();
+ for (int i = 0; i < num_threads; ++i)
+ {
+ Thread *thread = m_lldb_object_sp->GetThreadList().GetThreadAtIndex(i).get();
+ if (thread)
+ {
+ bool is_current_thread = false;
+ if (thread == cur_thread)
+ is_current_thread = true;
+ fprintf (out, " [%u] %c tid = 0x%4.4x, pc = 0x%16.16llx",
+ i,
+ (is_current_thread ? '*' : ' '),
+ thread->GetID(),
+ thread->GetRegisterContext()->GetPC());
+ const char *thread_name = thread->GetName();
+ if (thread_name && thread_name[0])
+ fprintf (out, ", name = %s", thread_name);
+ const char *queue_name = thread->GetQueueName();
+ if (queue_name && queue_name[0])
+ fprintf (out, ", queue = %s", queue_name);
+ fprintf (out, "\n");
+ }
+ }
+ }
+ }
+}
+
+SBThread
+SBProcess::GetThreadByID (tid_t sb_thread_id)
+{
+ SBThread thread;
+ if (m_lldb_object_sp)
+ thread.SetThread (m_lldb_object_sp->GetThreadList().FindThreadByID ((tid_t) sb_thread_id));
+ return thread;
+}
+
+void
+SBProcess::Backtrace (bool all_threads, uint32_t num_frames)
+{
+ if (m_lldb_object_sp)
+ {
+ if (!all_threads)
+ {
+ SBDebugger::UpdateCurrentThread (*this);
+ SBThread cur_thread = GetCurrentThread();
+ if (cur_thread.IsValid())
+ cur_thread.Backtrace (num_frames);
+ }
+ else
+ {
+ int num_threads = GetNumThreads ();
+ for (int i = 0; i < num_threads; ++i)
+ {
+ SBThread sb_thread = GetThreadAtIndex (i);
+ sb_thread.Backtrace (num_frames);
+ }
+ }
+ }
+}
+
+StateType
+SBProcess::GetStateFromEvent (const SBEvent &event)
+{
+ return Process::ProcessEventData::GetStateFromEvent (event.GetLLDBObjectPtr());
+}
+
+
+bool
+SBProcess::GetRestartedFromEvent (const SBEvent &event)
+{
+ return Process::ProcessEventData::GetRestartedFromEvent (event.GetLLDBObjectPtr());
+}
+
+SBProcess
+SBProcess::GetProcessFromEvent (const SBEvent &event)
+{
+ SBProcess process(Process::ProcessEventData::GetProcessFromEvent (event.GetLLDBObjectPtr()));
+ return process;
+}
+
+
+SBBroadcaster
+SBProcess::GetBroadcaster () const
+{
+ SBBroadcaster broadcaster(m_lldb_object_sp.get(), false);
+ return broadcaster;
+}
+
+lldb_private::Process *
+SBProcess::operator->() const
+{
+ return m_lldb_object_sp.get();
+}
+
+size_t
+SBProcess::ReadMemory (addr_t addr, void *dst, size_t dst_len, SBError &sb_error)
+{
+ size_t bytes_read = 0;
+
+ if (IsValid())
+ {
+ Error error;
+ bytes_read = m_lldb_object_sp->ReadMemory (addr, dst, dst_len, error);
+ sb_error.SetError (error);
+ }
+ else
+ {
+ sb_error.SetErrorString ("SBProcess is invalid");
+ }
+
+ return bytes_read;
+}
+
+size_t
+SBProcess::WriteMemory (addr_t addr, const void *src, size_t src_len, SBError &sb_error)
+{
+ size_t bytes_written = 0;
+
+ if (IsValid())
+ {
+ Error error;
+ bytes_written = m_lldb_object_sp->WriteMemory (addr, src, src_len, error);
+ sb_error.SetError (error);
+ }
+
+ return bytes_written;
+}
+
+// Mimic shared pointer...
+lldb_private::Process *
+SBProcess::get() const
+{
+ return m_lldb_object_sp.get();
+}
+
diff --git a/lldb/source/API/SBSourceManager.cpp b/lldb/source/API/SBSourceManager.cpp
new file mode 100644
index 00000000000..f2dcf6525ff
--- /dev/null
+++ b/lldb/source/API/SBSourceManager.cpp
@@ -0,0 +1,65 @@
+//===-- 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 "SBSourceManager.h"
+
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/SourceManager.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBSourceManager::SBSourceManager (SourceManager& source_manager) :
+ m_source_manager (source_manager)
+{
+}
+
+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,
+ FILE *f
+)
+{
+ if (f == NULL)
+ return 0;
+
+ if (file.IsValid())
+ {
+ StreamFile str (f);
+
+
+ return m_source_manager.DisplaySourceLinesWithLineNumbers (*file,
+ line,
+ context_before,
+ context_after,
+ current_line_cstr,
+ &str);
+ }
+ return 0;
+}
+
+SourceManager &
+SBSourceManager::GetLLDBManager ()
+{
+ return m_source_manager;
+}
diff --git a/lldb/source/API/SBStringList.cpp b/lldb/source/API/SBStringList.cpp
new file mode 100644
index 00000000000..b4cfb9b0c75
--- /dev/null
+++ b/lldb/source/API/SBStringList.cpp
@@ -0,0 +1,134 @@
+//===-- 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_lldb_object_ap ()
+{
+}
+
+SBStringList::SBStringList (const lldb_private::StringList *lldb_strings_ptr) :
+ m_lldb_object_ap ()
+{
+ if (lldb_strings_ptr)
+ m_lldb_object_ap.reset (new lldb_private::StringList (*lldb_strings_ptr));
+}
+
+SBStringList::SBStringList (const SBStringList &rhs) :
+ m_lldb_object_ap ()
+{
+ if (rhs.IsValid())
+ m_lldb_object_ap.reset (new lldb_private::StringList(*rhs));
+}
+
+
+
+SBStringList::~SBStringList ()
+{
+}
+
+
+const SBStringList &
+SBStringList::operator = (const SBStringList &rhs)
+{
+ if (rhs.IsValid())
+ m_lldb_object_ap.reset (new lldb_private::StringList(*rhs));
+
+ return *this;
+}
+
+const lldb_private::StringList *
+SBStringList::operator->() const
+{
+ return m_lldb_object_ap.get();
+}
+
+const lldb_private::StringList &
+SBStringList::operator*() const
+{
+ return *m_lldb_object_ap;
+}
+
+bool
+SBStringList::IsValid() const
+{
+ return (m_lldb_object_ap.get() != NULL);
+}
+
+void
+SBStringList::AppendString (const char *str)
+{
+ if (str != NULL)
+ {
+ if (IsValid())
+ m_lldb_object_ap->AppendString (str);
+ else
+ m_lldb_object_ap.reset (new lldb_private::StringList (str));
+ }
+
+}
+
+void
+SBStringList::AppendList (const char **strv, int strc)
+{
+ if ((strv != NULL)
+ && (strc > 0))
+ {
+ if (IsValid())
+ m_lldb_object_ap->AppendList (strv, strc);
+ else
+ m_lldb_object_ap.reset (new lldb_private::StringList (strv, strc));
+ }
+}
+
+void
+SBStringList::AppendList (SBStringList strings)
+{
+ if (strings.IsValid())
+ {
+ if (! IsValid())
+ m_lldb_object_ap.reset (new lldb_private::StringList());
+ m_lldb_object_ap->AppendList (*(strings.m_lldb_object_ap));
+ }
+}
+
+uint32_t
+SBStringList::GetSize () const
+{
+ if (IsValid())
+ {
+ return m_lldb_object_ap->GetSize();
+ }
+ return 0;
+}
+
+const char *
+SBStringList::GetStringAtIndex (size_t idx)
+{
+ if (IsValid())
+ {
+ return m_lldb_object_ap->GetStringAtIndex (idx);
+ }
+ return NULL;
+}
+
+void
+SBStringList::Clear ()
+{
+ if (IsValid())
+ {
+ m_lldb_object_ap->Clear();
+ }
+}
diff --git a/lldb/source/API/SBSymbol.cpp b/lldb/source/API/SBSymbol.cpp
new file mode 100644
index 00000000000..8500c8bd8a6
--- /dev/null
+++ b/lldb/source/API/SBSymbol.cpp
@@ -0,0 +1,64 @@
+//===-- 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/Symbol/Symbol.h"
+
+using namespace lldb;
+
+
+SBSymbol::SBSymbol () :
+ m_lldb_object_ptr (NULL)
+{
+}
+
+SBSymbol::SBSymbol (lldb_private::Symbol *lldb_object_ptr) :
+ m_lldb_object_ptr (lldb_object_ptr)
+{
+}
+
+SBSymbol::~SBSymbol ()
+{
+ m_lldb_object_ptr = NULL;
+}
+
+bool
+SBSymbol::IsValid () const
+{
+ return m_lldb_object_ptr != NULL;
+}
+
+const char *
+SBSymbol::GetName() const
+{
+ if (m_lldb_object_ptr)
+ return m_lldb_object_ptr->GetMangled().GetName().AsCString();
+ return NULL;
+}
+
+const char *
+SBSymbol::GetMangledName () const
+{
+ if (m_lldb_object_ptr)
+ return m_lldb_object_ptr->GetMangled().GetMangledName().AsCString();
+ return NULL;
+}
+
+
+bool
+SBSymbol::operator == (const SBSymbol &rhs) const
+{
+ return m_lldb_object_ptr == rhs.m_lldb_object_ptr;
+}
+
+bool
+SBSymbol::operator != (const SBSymbol &rhs) const
+{
+ return m_lldb_object_ptr != rhs.m_lldb_object_ptr;
+}
diff --git a/lldb/source/API/SBSymbolContext.cpp b/lldb/source/API/SBSymbolContext.cpp
new file mode 100644
index 00000000000..dec85295213
--- /dev/null
+++ b/lldb/source/API/SBSymbolContext.cpp
@@ -0,0 +1,133 @@
+//===-- 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/Symbol/SymbolContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+SBSymbolContext::SBSymbolContext () :
+ m_lldb_object_ap ()
+{
+}
+
+SBSymbolContext::SBSymbolContext (const SymbolContext *sc_ptr) :
+ m_lldb_object_ap ()
+{
+ if (sc_ptr)
+ m_lldb_object_ap.reset (new SymbolContext (*sc_ptr));
+}
+
+SBSymbolContext::SBSymbolContext (const SBSymbolContext& rhs) :
+ m_lldb_object_ap ()
+{
+ if (rhs.IsValid())
+ *m_lldb_object_ap = *rhs.m_lldb_object_ap;
+}
+
+SBSymbolContext::~SBSymbolContext ()
+{
+}
+
+const SBSymbolContext &
+SBSymbolContext::operator = (const SBSymbolContext &rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ m_lldb_object_ap.reset (new lldb_private::SymbolContext(*rhs.m_lldb_object_ap.get()));
+ }
+ return *this;
+}
+
+void
+SBSymbolContext::SetSymbolContext (const SymbolContext *sc_ptr)
+{
+ if (sc_ptr)
+ {
+ if (m_lldb_object_ap.get())
+ *m_lldb_object_ap = *sc_ptr;
+ else
+ m_lldb_object_ap.reset (new SymbolContext (*sc_ptr));
+ }
+ else
+ {
+ if (m_lldb_object_ap.get())
+ m_lldb_object_ap->Clear();
+ }
+}
+
+bool
+SBSymbolContext::IsValid () const
+{
+ return m_lldb_object_ap.get() != NULL;
+}
+
+
+
+SBModule
+SBSymbolContext::GetModule ()
+{
+ SBModule sb_module;
+ if (m_lldb_object_ap.get())
+ sb_module.SetModule(m_lldb_object_ap->module_sp);
+ return sb_module;
+}
+
+SBCompileUnit
+SBSymbolContext::GetCompileUnit ()
+{
+ return SBCompileUnit (m_lldb_object_ap.get() ? m_lldb_object_ap->comp_unit : NULL);
+}
+
+SBFunction
+SBSymbolContext::GetFunction ()
+{
+ return SBFunction (m_lldb_object_ap.get() ? m_lldb_object_ap->function : NULL);
+}
+
+SBBlock
+SBSymbolContext::GetBlock ()
+{
+ return SBBlock (m_lldb_object_ap.get() ? m_lldb_object_ap->block : NULL);
+}
+
+SBLineEntry
+SBSymbolContext::GetLineEntry ()
+{
+ SBLineEntry sb_line_entry;
+ if (m_lldb_object_ap.get())
+ sb_line_entry.SetLineEntry (m_lldb_object_ap->line_entry);
+
+ return sb_line_entry;
+}
+
+SBSymbol
+SBSymbolContext::GetSymbol ()
+{
+ return SBSymbol (m_lldb_object_ap.get() ? m_lldb_object_ap->symbol : NULL);
+}
+
+lldb_private::SymbolContext*
+SBSymbolContext::operator->() const
+{
+ return m_lldb_object_ap.get();
+}
+
+lldb_private::SymbolContext *
+SBSymbolContext::GetLLDBObjectPtr() const
+{
+ return m_lldb_object_ap.get();
+}
+
+
+
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
new file mode 100644
index 00000000000..799be37e873
--- /dev/null
+++ b/lldb/source/API/SBTarget.cpp
@@ -0,0 +1,553 @@
+//===-- 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 "SBTarget.h"
+
+#include "lldb/lldb-include.h"
+
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBModule.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/Args.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/STLUtils.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"
+
+#include "SBDebugger.h"
+#include "SBProcess.h"
+#include "SBListener.h"
+#include "SBBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define DEFAULT_DISASM_BYTE_SIZE 32
+
+//----------------------------------------------------------------------
+// SBTarget constructor
+//----------------------------------------------------------------------
+SBTarget::SBTarget ()
+{
+}
+
+SBTarget::SBTarget (const SBTarget& rhs) :
+ m_target_sp (rhs.m_target_sp)
+{
+}
+
+SBTarget::SBTarget(const TargetSP& target_sp) :
+ m_target_sp (target_sp)
+{
+}
+
+const SBTarget&
+SBTarget::Assign (const SBTarget& rhs)
+{
+ if (this != &rhs)
+ {
+ m_target_sp = rhs.m_target_sp;
+ }
+ return *this;
+}
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SBTarget::~SBTarget()
+{
+}
+
+bool
+SBTarget::IsValid () const
+{
+ return m_target_sp.get() != NULL;
+}
+
+SBProcess
+SBTarget::GetProcess ()
+{
+ SBProcess sb_process;
+ if (IsValid())
+ sb_process.SetProcess (m_target_sp->GetProcessSP());
+ return sb_process;
+}
+
+SBProcess
+SBTarget::CreateProcess ()
+{
+ SBProcess sb_process;
+
+ if (IsValid())
+ {
+ SBListener sb_listener = SBDebugger::GetListener();
+ if (sb_listener.IsValid())
+ sb_process.SetProcess (m_target_sp->CreateProcess (*sb_listener));
+ }
+ return sb_process;
+}
+
+SBProcess
+SBTarget::LaunchProcess
+(
+ char const **argv,
+ char const **envp,
+ const char *tty,
+ bool stop_at_entry
+)
+{
+ SBProcess process(GetProcess ());
+ if (!process.IsValid())
+ process = CreateProcess();
+ if (process.IsValid())
+ {
+ Error error (process->Launch (argv, envp, tty, tty, tty));
+ if (error.Success())
+ {
+ if (!stop_at_entry)
+ {
+ StateType state = process->WaitForProcessToStop (NULL);
+ if (state == eStateStopped)
+ process->Resume();
+ }
+ }
+ }
+ return process;
+}
+
+SBFileSpec
+SBTarget::GetExecutable ()
+{
+ SBFileSpec exe_file_spec;
+ if (IsValid())
+ {
+ ModuleSP exe_module_sp (m_target_sp->GetExecutableModule ());
+ if (exe_module_sp)
+ exe_file_spec.SetFileSpec (exe_module_sp->GetFileSpec());
+ }
+ return exe_file_spec;
+}
+
+
+bool
+SBTarget::DeleteTargetFromList (TargetList *list)
+{
+ if (IsValid())
+ return list->DeleteTarget (m_target_sp);
+ else
+ return false;
+}
+
+bool
+SBTarget::MakeCurrentTarget ()
+{
+ if (IsValid())
+ {
+ Debugger::GetSharedInstance().GetTargetList().SetCurrentTarget (m_target_sp.get());
+ return true;
+ }
+ return false;
+}
+
+bool
+SBTarget::operator == (const SBTarget &rhs) const
+{
+ return m_target_sp.get() == rhs.m_target_sp.get();
+}
+
+bool
+SBTarget::operator != (const SBTarget &rhs) const
+{
+ return m_target_sp.get() != rhs.m_target_sp.get();
+}
+
+lldb_private::Target *
+SBTarget::GetLLDBObjectPtr()
+{
+ return m_target_sp.get();
+}
+const lldb_private::Target *
+SBTarget::GetLLDBObjectPtr() const
+{
+ return m_target_sp.get();
+}
+
+SBBreakpoint
+SBTarget::BreakpointCreateByLocation (const char *file, uint32_t line)
+{
+ SBBreakpoint sb_bp;
+ if (file != NULL && line != 0)
+ sb_bp = BreakpointCreateByLocation (SBFileSpec (file), line);
+ return sb_bp;
+}
+
+SBBreakpoint
+SBTarget::BreakpointCreateByLocation (const SBFileSpec &sb_file_spec, uint32_t line)
+{
+ SBBreakpoint sb_bp;
+ if (m_target_sp.get() && line != 0)
+ *sb_bp = m_target_sp->CreateBreakpoint (NULL, *sb_file_spec, line, true, false);
+ return sb_bp;
+}
+
+SBBreakpoint
+SBTarget::BreakpointCreateByName (const char *symbol_name, const char *module_name)
+{
+ SBBreakpoint sb_bp;
+ if (m_target_sp.get() && symbol_name && symbol_name[0])
+ {
+ if (module_name && module_name[0])
+ {
+ FileSpec module_file_spec(module_name);
+ *sb_bp = m_target_sp->CreateBreakpoint (&module_file_spec, symbol_name, false);
+ }
+ else
+ {
+ *sb_bp = m_target_sp->CreateBreakpoint (NULL, symbol_name, false);
+ }
+ }
+ return sb_bp;
+}
+
+SBBreakpoint
+SBTarget::BreakpointCreateByRegex (const char *symbol_name_regex, const char *module_name)
+{
+ SBBreakpoint sb_bp;
+ if (m_target_sp.get() && symbol_name_regex && symbol_name_regex[0])
+ {
+ RegularExpression regexp(symbol_name_regex);
+
+ if (module_name && module_name[0])
+ {
+ FileSpec module_file_spec(module_name);
+
+ *sb_bp = m_target_sp->CreateBreakpoint (&module_file_spec, regexp, false);
+ }
+ else
+ {
+ *sb_bp = m_target_sp->CreateBreakpoint (NULL, regexp, false);
+ }
+ }
+ return sb_bp;
+}
+
+
+
+SBBreakpoint
+SBTarget::BreakpointCreateByAddress (addr_t address)
+{
+ SBBreakpoint sb_bp;
+ if (m_target_sp.get())
+ *sb_bp = m_target_sp->CreateBreakpoint (address, false);
+ return sb_bp;
+}
+
+void
+SBTarget::ListAllBreakpoints ()
+{
+ FILE *out_file = SBDebugger::GetOutputFileHandle();
+
+ if (out_file == NULL)
+ return;
+
+ if (IsValid())
+ {
+ const BreakpointList &bp_list = m_target_sp->GetBreakpointList();
+ size_t num_bps = bp_list.GetSize();
+ for (int i = 0; i < num_bps; ++i)
+ {
+ SBBreakpoint sb_breakpoint (bp_list.GetBreakpointByIndex (i));
+ sb_breakpoint.GetDescription (out_file, "full");
+ }
+ }
+}
+
+SBBreakpoint
+SBTarget::FindBreakpointByID (break_id_t bp_id)
+{
+ SBBreakpoint sb_breakpoint;
+ if (m_target_sp && bp_id != LLDB_INVALID_BREAK_ID)
+ *sb_breakpoint = m_target_sp->GetBreakpointByID (bp_id);
+ return sb_breakpoint;
+}
+
+
+bool
+SBTarget::BreakpointDelete (break_id_t bp_id)
+{
+ if (m_target_sp)
+ return m_target_sp->RemoveBreakpointByID (bp_id);
+ return false;
+}
+
+bool
+SBTarget::EnableAllBreakpoints ()
+{
+ if (m_target_sp)
+ {
+ m_target_sp->EnableAllBreakpoints ();
+ return true;
+ }
+ return false;
+}
+
+bool
+SBTarget::DisableAllBreakpoints ()
+{
+ if (m_target_sp)
+ {
+ m_target_sp->DisableAllBreakpoints ();
+ return true;
+ }
+ return false;
+}
+
+bool
+SBTarget::DeleteAllBreakpoints ()
+{
+ if (m_target_sp)
+ {
+ m_target_sp->RemoveAllBreakpoints ();
+ return true;
+ }
+ return false;
+}
+
+
+uint32_t
+SBTarget::GetNumModules () const
+{
+ if (m_target_sp)
+ return m_target_sp->GetImages().GetSize();
+ return 0;
+}
+
+SBModule
+SBTarget::FindModule (const SBFileSpec &sb_file_spec)
+{
+ SBModule sb_module;
+ if (m_target_sp && sb_file_spec.IsValid())
+ sb_module.SetModule (m_target_sp->GetImages().FindFirstModuleForFileSpec (*sb_file_spec, NULL));
+ return sb_module;
+}
+
+SBModule
+SBTarget::GetModuleAtIndex (uint32_t idx)
+{
+ SBModule sb_module;
+ if (m_target_sp)
+ sb_module.SetModule(m_target_sp->GetImages().GetModuleAtIndex(idx));
+ return sb_module;
+}
+
+
+SBBroadcaster
+SBTarget::GetBroadcaster () const
+{
+ SBBroadcaster broadcaster(m_target_sp.get(), false);
+ return broadcaster;
+}
+
+void
+SBTarget::Disassemble (lldb::addr_t file_address_start, lldb::addr_t file_address_end, const char *module_name)
+{
+ if (file_address_start == LLDB_INVALID_ADDRESS)
+ return;
+
+ FILE *out = SBDebugger::GetOutputFileHandle();
+ if (out == NULL)
+ return;
+
+ if (IsValid())
+ {
+ SBModule module;
+ if (module_name != NULL)
+ {
+ SBFileSpec file_spec (module_name);
+ module = FindModule (file_spec);
+ }
+ ArchSpec arch (m_target_sp->GetArchitecture());
+ if (!arch.IsValid())
+ return;
+ Disassembler *disassembler = Disassembler::FindPlugin (arch);
+ if (disassembler == NULL)
+ return;
+
+ // For now, we need a process; the disassembly functions insist. If we don't have one already,
+ // make one.
+
+ SBProcess process = GetProcess();
+ if (! process.IsValid())
+ process = CreateProcess();
+
+ ExecutionContext exe_context (process.get());
+
+ if (file_address_end == LLDB_INVALID_ADDRESS
+ || file_address_end < file_address_start)
+ file_address_end = file_address_start + DEFAULT_DISASM_BYTE_SIZE;
+
+ // TO BE FIXED: SOMEHOW WE NEED TO SPECIFY/USE THE MODULE, IF THE USER SPECIFIED ONE. I'M NOT
+ // SURE HOW TO DO THAT AT THE MOMENT. WE ALSO NEED TO FIGURE OUT WHAT TO DO IF THERE ARE MULTIPLE
+ // MODULES CONTAINING THE SPECIFIED ADDRESSES (E.G. THEY HAVEN'T ALL LOADED & BEEN GIVEN UNIQUE
+ // ADDRESSES YET).
+
+ DataExtractor data;
+ size_t bytes_disassembled = disassembler->ParseInstructions (&exe_context, eAddressTypeLoad,
+ file_address_start,
+ file_address_end - file_address_start, data);
+
+ if (bytes_disassembled > 0)
+ {
+ size_t num_instructions = disassembler->GetInstructionList().GetSize();
+ uint32_t offset = 0;
+ StreamFile out_stream (out);
+
+ for (size_t i = 0; i < num_instructions; ++i)
+ {
+ Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i);
+ if (inst)
+ {
+ lldb::addr_t cur_addr = file_address_start + offset;
+ size_t inst_byte_size = inst->GetByteSize();
+ inst->Dump (&out_stream, cur_addr, &data, offset, exe_context, false);
+ out_stream.EOL();
+ offset += inst_byte_size;
+ }
+ }
+ }
+ }
+}
+
+void
+SBTarget::Disassemble (const char *function_name, const char *module_name)
+{
+ if (function_name == NULL)
+ return;
+
+ FILE *out = SBDebugger::GetOutputFileHandle();
+ if (out == NULL)
+ return;
+
+ if (IsValid())
+ {
+ SBModule module;
+
+ if (module_name != NULL)
+ {
+ SBFileSpec file_spec (module_name);
+ module = FindModule (file_spec);
+ }
+
+ ArchSpec arch (m_target_sp->GetArchitecture());
+ if (!arch.IsValid())
+ return;
+
+ Disassembler *disassembler = Disassembler::FindPlugin (arch);
+ if (disassembler == NULL)
+ return;
+
+ // For now, we need a process; the disassembly functions insist. If we don't have one already,
+ // make one.
+
+ SBProcess process = GetProcess();
+ if (! process.IsValid()
+ || process.GetProcessID() == 0)
+ {
+ fprintf (out, "Cannot disassemble functions until after process has launched.\n");
+ return;
+ }
+
+ ExecutionContext exe_context (process.get());
+
+ FileSpec *containing_module = NULL;
+
+ if (module_name != NULL)
+ containing_module = new FileSpec (module_name);
+
+ SearchFilterSP filter_sp (m_target_sp->GetSearchFilterForModule (containing_module));
+ AddressResolverSP resolver_sp (new AddressResolverName (function_name));
+
+ resolver_sp->ResolveAddress (*filter_sp);
+
+ size_t num_matches_found = resolver_sp->GetNumberOfAddresses();
+
+ if (num_matches_found == 1)
+ {
+ DataExtractor data;
+
+ AddressRange func_addresses = resolver_sp->GetAddressRangeAtIndex (0);
+ Address start_addr = func_addresses.GetBaseAddress();
+ lldb::addr_t num_bytes = func_addresses.GetByteSize();
+
+ lldb::addr_t addr = LLDB_INVALID_ADDRESS;
+ size_t bytes_disassembled = 0;
+
+
+ if (process.GetProcessID() == 0)
+ {
+ // Leave this branch in for now, but it should not be reached, since we exit above if the PID is 0.
+ addr = start_addr.GetFileAddress ();
+ bytes_disassembled = disassembler->ParseInstructions (&exe_context, eAddressTypeFile, addr,
+ num_bytes, data);
+
+ }
+ else
+ {
+ addr = start_addr.GetLoadAddress (process.get());
+ bytes_disassembled = disassembler->ParseInstructions (&exe_context, eAddressTypeLoad, addr,
+ num_bytes, data);
+
+ }
+
+ if (bytes_disassembled > 0)
+ {
+ size_t num_instructions = disassembler->GetInstructionList().GetSize();
+ uint32_t offset = 0;
+ StreamFile out_stream (out);
+
+ for (size_t i = 0; i < num_instructions; ++i)
+ {
+ Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i);
+ if (inst)
+ {
+ lldb::addr_t cur_addr = addr + offset;
+ size_t inst_byte_size = inst->GetByteSize();
+ inst->Dump (&out_stream, cur_addr, &data, offset, exe_context, false);
+ out_stream.EOL();
+ offset += inst_byte_size;
+ }
+ }
+ }
+ }
+ else if (num_matches_found > 1)
+ {
+ // TO BE FIXED: Eventually we want to list/disassemble all functions found.
+ fprintf (out, "Function '%s' was found in multiple modules; please specify the desired module name.\n",
+ function_name);
+ }
+ else
+ fprintf (out, "Function '%s' was not found.\n", function_name);
+ }
+}
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
new file mode 100644
index 00000000000..4ae9ba17525
--- /dev/null
+++ b/lldb/source/API/SBThread.cpp
@@ -0,0 +1,551 @@
+//===-- 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 "SBThread.h"
+
+#include "lldb/API/SBSymbolContext.h"
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanContinue.h"
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepRange.h"
+#include "lldb/Target/ThreadPlanStepInRange.h"
+
+
+#include "SBAddress.h"
+#include "SBFrame.h"
+#include "SBSourceManager.h"
+#include "SBDebugger.h"
+#include "SBProcess.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBThread::SBThread () :
+ m_lldb_object_sp ()
+{
+}
+
+//----------------------------------------------------------------------
+// Thread constructor
+//----------------------------------------------------------------------
+SBThread::SBThread (const ThreadSP& lldb_object_sp) :
+ m_lldb_object_sp (lldb_object_sp)
+{
+}
+
+SBThread::SBThread (const SBThread &rhs)
+{
+ m_lldb_object_sp = rhs.m_lldb_object_sp;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SBThread::~SBThread()
+{
+}
+
+bool
+SBThread::IsValid() const
+{
+ return m_lldb_object_sp != NULL;
+}
+
+StopReason
+SBThread::GetStopReason()
+{
+ if (m_lldb_object_sp)
+ {
+ lldb_private::Thread::StopInfo thread_stop_info;
+ if (m_lldb_object_sp->GetStopInfo(&thread_stop_info))
+ return thread_stop_info.GetStopReason();
+ }
+ return eStopReasonInvalid;
+}
+
+size_t
+SBThread::GetStopDescription (char *dst, size_t dst_len)
+{
+ if (m_lldb_object_sp)
+ {
+ lldb_private::Thread::StopInfo thread_stop_info;
+ if (m_lldb_object_sp->GetStopInfo(&thread_stop_info))
+ {
+ const char *stop_desc = thread_stop_info.GetStopDescription();
+ if (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
+ {
+ const char *stop_desc = NULL;
+ size_t stop_desc_len = 0;
+ switch (thread_stop_info.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 = m_lldb_object_sp->GetProcess().GetUnixSignals ().GetSignalAsCString (thread_stop_info.GetSignal());
+ 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;
+ }
+
+ if (stop_desc && stop_desc[0])
+ {
+ 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;
+ }
+ }
+ }
+ }
+ if (dst)
+ *dst = 0;
+ return 0;
+}
+
+void
+SBThread::SetThread (const ThreadSP& lldb_object_sp)
+{
+ m_lldb_object_sp = lldb_object_sp;
+}
+
+
+lldb::tid_t
+SBThread::GetThreadID () const
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetID();
+ else
+ return LLDB_INVALID_THREAD_ID;
+}
+
+uint32_t
+SBThread::GetIndexID () const
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetIndexID();
+ return LLDB_INVALID_INDEX32;
+}
+const char *
+SBThread::GetName () const
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetName();
+ return NULL;
+}
+
+const char *
+SBThread::GetQueueName () const
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetQueueName();
+ return NULL;
+}
+
+
+void
+SBThread::DisplayFramesForCurrentContext (FILE *out,
+ FILE *err,
+ uint32_t first_frame,
+ uint32_t num_frames,
+ bool show_frame_info,
+ uint32_t num_frames_with_source,
+ uint32_t source_lines_before,
+ uint32_t source_lines_after)
+{
+ if ((out == NULL) || (err == NULL))
+ return;
+
+ if (m_lldb_object_sp)
+ {
+ uint32_t num_stack_frames = m_lldb_object_sp->GetStackFrameCount ();
+ StackFrameSP frame_sp;
+ int frame_idx = 0;
+
+ for (frame_idx = first_frame; frame_idx < first_frame + num_frames; ++frame_idx)
+ {
+ if (frame_idx >= num_stack_frames)
+ break;
+
+ frame_sp = m_lldb_object_sp->GetStackFrameAtIndex (frame_idx);
+ if (!frame_sp)
+ break;
+
+ SBFrame sb_frame (frame_sp);
+ if (DisplaySingleFrameForCurrentContext (out,
+ err,
+ sb_frame,
+ show_frame_info,
+ num_frames_with_source > first_frame - frame_idx,
+ source_lines_before,
+ source_lines_after) == false)
+ break;
+ }
+ }
+}
+
+bool
+SBThread::DisplaySingleFrameForCurrentContext (FILE *out,
+ FILE *err,
+ SBFrame &frame,
+ bool show_frame_info,
+ bool show_source,
+ uint32_t source_lines_after,
+ uint32_t source_lines_before)
+{
+ bool success = false;
+
+ if ((out == NULL) || (err == NULL))
+ return false;
+
+ if (m_lldb_object_sp && frame.IsValid())
+ {
+
+ StreamFile str (out);
+
+ SBSymbolContext sc(frame.GetSymbolContext(eSymbolContextEverything));
+
+ if (show_frame_info && sc.IsValid())
+ {
+ user_id_t frame_idx = (user_id_t) frame.GetFrameID();
+ lldb::addr_t pc = frame.GetPC();
+ ::fprintf (out,
+ " frame #%u: tid = 0x%4.4x, pc = 0x%llx ",
+ frame_idx,
+ GetThreadID(),
+ pc);
+ sc->DumpStopContext (&str, &m_lldb_object_sp->GetProcess(), *frame.GetPCAddress());
+ fprintf (out, "\n");
+ success = true;
+ }
+
+ SBCompileUnit comp_unit(sc.GetCompileUnit());
+ if (show_source && comp_unit.IsValid())
+ {
+ success = false;
+ SBLineEntry line_entry;
+ if (line_entry.IsValid())
+ {
+ SBSourceManager& source_manager = SBDebugger::GetSourceManager();
+ SBFileSpec line_entry_file_spec = line_entry.GetFileSpec();
+
+ if (line_entry_file_spec.IsValid())
+ {
+ source_manager.DisplaySourceLinesWithLineNumbers (line_entry_file_spec,
+ line_entry.GetLine(),
+ source_lines_after,
+ source_lines_before, "->",
+ out);
+ success = true;
+ }
+ }
+ }
+ }
+ return success;
+}
+
+void
+SBThread::StepOver (lldb::RunMode stop_other_threads)
+{
+ if (m_lldb_object_sp)
+ {
+ bool abort_other_plans = true;
+ StackFrameSP frame_sp(m_lldb_object_sp->GetStackFrameAtIndex (0));
+
+ if (frame_sp)
+ {
+ if (frame_sp->HasDebugInformation ())
+ {
+ SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
+ m_lldb_object_sp->QueueThreadPlanForStepRange (abort_other_plans,
+ eStepTypeOver,
+ sc.line_entry.range,
+ sc,
+ stop_other_threads);
+
+ }
+ else
+ {
+ m_lldb_object_sp->QueueThreadPlanForStepSingleInstruction (true,
+ abort_other_plans,
+ stop_other_threads);
+ }
+ }
+
+ Process &process = m_lldb_object_sp->GetProcess();
+ // Why do we need to set the current thread by ID here???
+ process.GetThreadList().SetCurrentThreadByID (m_lldb_object_sp->GetID());
+ process.Resume();
+ }
+}
+
+void
+SBThread::StepInto (lldb::RunMode stop_other_threads)
+{
+ if (m_lldb_object_sp)
+ {
+ bool abort_other_plans = true;
+
+ StackFrameSP frame_sp(m_lldb_object_sp->GetStackFrameAtIndex (0));
+
+ if (frame_sp && frame_sp->HasDebugInformation ())
+ {
+ SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
+ ThreadPlan *new_plan = m_lldb_object_sp->QueueThreadPlanForStepRange (abort_other_plans,
+ eStepTypeInto,
+ sc.line_entry.range,
+ sc,
+ stop_other_threads);
+ if (new_plan)
+ {
+ ThreadPlanStepInRange *real_plan = dynamic_cast<ThreadPlanStepInRange *> (new_plan);
+ if (real_plan)
+ {
+ bool avoid_no_debug = true;
+ if (avoid_no_debug)
+ real_plan->GetFlags().Set (ThreadPlanShouldStopHere::eAvoidNoDebug);
+ else
+ real_plan->GetFlags().Clear (ThreadPlanShouldStopHere::eAvoidNoDebug);
+ }
+ }
+ }
+ else
+ {
+ m_lldb_object_sp->QueueThreadPlanForStepSingleInstruction (false,
+ abort_other_plans,
+ stop_other_threads);
+ }
+
+ Process &process = m_lldb_object_sp->GetProcess();
+ // Why do we need to set the current thread by ID here???
+ process.GetThreadList().SetCurrentThreadByID (m_lldb_object_sp->GetID());
+ process.Resume();
+
+ }
+}
+
+void
+SBThread::StepOut ()
+{
+ if (m_lldb_object_sp)
+ {
+ bool abort_other_plans = true;
+ bool stop_other_threads = true;
+
+ m_lldb_object_sp->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, stop_other_threads, eVoteYes, eVoteNoOpinion);
+
+ Process &process = m_lldb_object_sp->GetProcess();
+ process.GetThreadList().SetCurrentThreadByID (m_lldb_object_sp->GetID());
+ process.Resume();
+ }
+}
+
+void
+SBThread::StepInstruction (bool step_over)
+{
+ if (m_lldb_object_sp)
+ {
+ m_lldb_object_sp->QueueThreadPlanForStepSingleInstruction (step_over, true, true);
+ Process &process = m_lldb_object_sp->GetProcess();
+ process.GetThreadList().SetCurrentThreadByID (m_lldb_object_sp->GetID());
+ process.Resume();
+ }
+}
+
+void
+SBThread::RunToAddress (lldb::addr_t addr)
+{
+ if (m_lldb_object_sp)
+ {
+ bool abort_other_plans = true;
+ bool stop_other_threads = true;
+
+ Address target_addr (NULL, addr);
+
+ m_lldb_object_sp->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads);
+ Process &process = m_lldb_object_sp->GetProcess();
+ process.GetThreadList().SetCurrentThreadByID (m_lldb_object_sp->GetID());
+ process.Resume();
+ }
+
+}
+
+void
+SBThread::Backtrace (uint32_t num_frames)
+{
+ bool all_frames = false;
+ if (num_frames < 1)
+ all_frames = true;
+
+ FILE *out = SBDebugger::GetOutputFileHandle();
+ FILE *err = SBDebugger::GetErrorFileHandle();
+
+ if ((out == NULL) || (err == NULL))
+ return;
+
+ if (m_lldb_object_sp)
+ {
+ if (out && err)
+ {
+ int max_num_frames = m_lldb_object_sp->GetStackFrameCount();
+ int last_frame = max_num_frames;
+
+ if (!all_frames && (num_frames < last_frame))
+ last_frame = num_frames;
+
+ StackFrameSP frame_sp;
+ for (int i = 0; i < last_frame; ++i)
+ {
+ frame_sp = m_lldb_object_sp->GetStackFrameAtIndex (i);
+ if (!frame_sp)
+ break;
+
+ SBFrame sb_frame (frame_sp);
+ if (DisplaySingleFrameForCurrentContext ((FILE *) out, (FILE *) err, sb_frame, true, false, 0, 0) == false)
+ break;
+ }
+ }
+ }
+}
+
+SBProcess
+SBThread::GetProcess ()
+{
+ SBProcess process;
+ if (m_lldb_object_sp)
+ {
+ // Have to go up to the target so we can get a shared pointer to our process...
+ process.SetProcess(m_lldb_object_sp->GetProcess().GetTarget().GetProcessSP());
+ }
+ return process;
+}
+
+uint32_t
+SBThread::GetNumFrames ()
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetStackFrameCount();
+ return 0;
+}
+
+SBFrame
+SBThread::GetFrameAtIndex (uint32_t idx)
+{
+ SBFrame sb_frame;
+ if (m_lldb_object_sp)
+ sb_frame.SetFrame (m_lldb_object_sp->GetStackFrameAtIndex (idx));
+ return sb_frame;
+}
+
+const lldb::SBThread &
+SBThread::operator = (const lldb::SBThread &rhs)
+{
+ m_lldb_object_sp = rhs.m_lldb_object_sp;
+ return *this;
+}
+
+bool
+SBThread::operator == (const SBThread &rhs) const
+{
+ return m_lldb_object_sp.get() == rhs.m_lldb_object_sp.get();
+}
+
+bool
+SBThread::operator != (const SBThread &rhs) const
+{
+ return m_lldb_object_sp.get() != rhs.m_lldb_object_sp.get();
+}
+
+lldb_private::Thread *
+SBThread::GetLLDBObjectPtr ()
+{
+ return m_lldb_object_sp.get();
+}
+
+const lldb_private::Thread *
+SBThread::operator->() const
+{
+ return m_lldb_object_sp.get();
+}
+
+const lldb_private::Thread &
+SBThread::operator*() const
+{
+ return *m_lldb_object_sp;
+}
+
+lldb_private::Thread *
+SBThread::operator->()
+{
+ return m_lldb_object_sp.get();
+}
+
+lldb_private::Thread &
+SBThread::operator*()
+{
+ return *m_lldb_object_sp;
+}
diff --git a/lldb/source/API/SBType.cpp b/lldb/source/API/SBType.cpp
new file mode 100644
index 00000000000..d8e836e3a8c
--- /dev/null
+++ b/lldb/source/API/SBType.cpp
@@ -0,0 +1,23 @@
+//===-- 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 "lldb/API/SBType.h"
+#include "lldb/Symbol/ClangASTContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+bool
+SBType::IsPointerType (void *opaque_type)
+{
+ return ClangASTContext::IsPointerType (opaque_type);
+}
+
+
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
new file mode 100644
index 00000000000..21f9a0eed94
--- /dev/null
+++ b/lldb/source/API/SBValue.cpp
@@ -0,0 +1,372 @@
+//===-- 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 "SBValue.h"
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+
+#include "SBProcess.h"
+#include "SBTarget.h"
+#include "SBThread.h"
+#include "SBFrame.h"
+#include "SBDebugger.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBValue::SBValue () :
+ m_lldb_object_sp ()
+{
+}
+
+SBValue::SBValue (const lldb::ValueObjectSP &value_sp) :
+ m_lldb_object_sp (value_sp)
+{
+}
+
+SBValue::~SBValue()
+{
+}
+
+bool
+SBValue::IsValid () const
+{
+ return (m_lldb_object_sp.get() != NULL);
+}
+
+void
+SBValue::Print (FILE *out_file, SBFrame *frame, bool print_type, bool print_value)
+{
+ if (out_file == NULL)
+ return;
+
+ if (IsValid())
+ {
+
+ SBThread sb_thread = frame->GetThread();
+ SBProcess sb_process = sb_thread.GetProcess();
+
+ lldb_private::StackFrame *lldb_frame = frame->GetLLDBObjectPtr();
+ lldb_private::Thread *lldb_thread = sb_thread.GetLLDBObjectPtr();
+ lldb_private::Process *lldb_process = sb_process.get();
+
+ lldb_private::ExecutionContext context (lldb_process, lldb_thread, lldb_frame);
+
+ lldb_private::StreamFile out_stream (out_file);
+
+ out_stream.Printf ("%s ", m_lldb_object_sp->GetName().AsCString (NULL));
+ if (! m_lldb_object_sp->IsInScope (lldb_frame))
+ out_stream.Printf ("[out-of-scope] ");
+ if (print_type)
+ {
+ out_stream.Printf ("(%s) ", m_lldb_object_sp->GetTypeName().AsCString ("<unknown-type>"));
+ }
+
+ if (print_value)
+ {
+ ExecutionContextScope *exe_scope = frame->get();
+ const char *val_cstr = m_lldb_object_sp->GetValueAsCString(exe_scope);
+ const char *err_cstr = m_lldb_object_sp->GetError().AsCString();
+
+ if (!err_cstr)
+ {
+ const char *sum_cstr = m_lldb_object_sp->GetSummaryAsCString(exe_scope);
+ const bool is_aggregate =
+ ClangASTContext::IsAggregateType (m_lldb_object_sp->GetOpaqueClangQualType());
+ if (val_cstr)
+ out_stream.Printf ("= %s ", val_cstr);
+
+ if (sum_cstr)
+ out_stream.Printf ("%s ", sum_cstr);
+
+ if (is_aggregate)
+ {
+ out_stream.PutChar ('{');
+ const uint32_t num_children = m_lldb_object_sp->GetNumChildren();
+ if (num_children)
+ {
+ out_stream.IndentMore();
+ for (uint32_t idx = 0; idx < num_children; ++idx)
+ {
+ lldb::ValueObjectSP child_sp (m_lldb_object_sp->GetChildAtIndex (idx, true));
+ if (child_sp.get())
+ {
+ out_stream.EOL();
+ out_stream.Indent();
+ out_stream.Printf ("%s (%s) = %s", child_sp.get()->GetName().AsCString (""),
+ child_sp.get()->GetTypeName().AsCString ("<unknown type>"),
+ child_sp.get()->GetValueAsCString(exe_scope));
+ }
+ }
+ out_stream.IndentLess();
+ }
+ out_stream.EOL();
+ out_stream.Indent ("}");
+ }
+ }
+ }
+ out_stream.EOL ();
+ }
+}
+
+const char *
+SBValue::GetName()
+{
+ if (IsValid())
+ return m_lldb_object_sp->GetName().AsCString();
+ else
+ return NULL;
+}
+
+const char *
+SBValue::GetTypeName ()
+{
+ if (IsValid())
+ return m_lldb_object_sp->GetTypeName().AsCString();
+ else
+ return NULL;
+}
+
+size_t
+SBValue::GetByteSize ()
+{
+ size_t result = 0;
+
+ if (IsValid())
+ result = m_lldb_object_sp->GetByteSize();
+
+ return result;
+}
+
+bool
+SBValue::IsInScope (const SBFrame &frame)
+{
+ bool result = false;
+
+ if (IsValid())
+ result = m_lldb_object_sp->IsInScope (frame.get());
+
+ return result;
+}
+
+const char *
+SBValue::GetValue (const SBFrame &frame)
+{
+ const char *value_string = NULL;
+ if ( m_lldb_object_sp)
+ value_string = m_lldb_object_sp->GetValueAsCString(frame.get());
+ return value_string;
+}
+
+bool
+SBValue::GetValueDidChange ()
+{
+ if (IsValid())
+ return m_lldb_object_sp->GetValueDidChange();
+ return false;
+}
+
+const char *
+SBValue::GetSummary (const SBFrame &frame)
+{
+ const char *value_string = NULL;
+ if ( m_lldb_object_sp)
+ value_string = m_lldb_object_sp->GetSummaryAsCString(frame.get());
+ return value_string;
+}
+
+const char *
+SBValue::GetLocation (const SBFrame &frame)
+{
+ const char *value_string = NULL;
+ if (IsValid())
+ value_string = m_lldb_object_sp->GetLocationAsCString(frame.get());
+ return value_string;
+}
+
+bool
+SBValue::SetValueFromCString (const SBFrame &frame, const char *value_str)
+{
+ bool success = false;
+ if (IsValid())
+ success = m_lldb_object_sp->SetValueFromCString (frame.get(), value_str);
+ return success;
+}
+
+SBValue
+SBValue::GetChildAtIndex (uint32_t idx)
+{
+ lldb::ValueObjectSP child_sp;
+
+ if (IsValid())
+ {
+ child_sp = m_lldb_object_sp->GetChildAtIndex (idx, true);
+ }
+
+ SBValue sb_value (child_sp);
+ return sb_value;
+}
+
+uint32_t
+SBValue::GetIndexOfChildWithName (const char *name)
+{
+ if (IsValid())
+ return m_lldb_object_sp->GetIndexOfChildWithName (ConstString(name));
+ return UINT32_MAX;
+}
+
+SBValue
+SBValue::GetChildMemberWithName (const char *name)
+{
+ lldb::ValueObjectSP child_sp;
+ const ConstString str_name (name);
+
+ if (IsValid())
+ {
+ child_sp = m_lldb_object_sp->GetChildMemberWithName (str_name, true);
+ }
+
+ SBValue sb_value (child_sp);
+ return sb_value;
+}
+
+
+uint32_t
+SBValue::GetNumChildren ()
+{
+ uint32_t num_children = 0;
+
+ if (IsValid())
+ {
+ num_children = m_lldb_object_sp->GetNumChildren();
+ }
+
+ return num_children;
+}
+
+bool
+SBValue::ValueIsStale ()
+{
+ bool result = true;
+
+ if (IsValid())
+ {
+ result = m_lldb_object_sp->GetValueIsValid();
+ }
+
+ return result;
+}
+
+
+SBValue
+SBValue::Dereference ()
+{
+ if (IsValid())
+ {
+ if (m_lldb_object_sp->IsPointerType())
+ {
+ return GetChildAtIndex(0);
+ }
+ }
+ return *this;
+}
+
+bool
+SBValue::TypeIsPtrType ()
+{
+ bool is_ptr_type = false;
+
+ if (IsValid())
+ {
+ is_ptr_type = m_lldb_object_sp->IsPointerType();
+ }
+
+ return is_ptr_type;
+}
+
+
+lldb_private::ExecutionContext
+SBValue::GetCurrentExecutionContext ()
+{
+ lldb_private::Process *process = NULL;
+ lldb_private::Thread *thread = NULL;
+ lldb_private::StackFrame *frame = NULL;
+
+ SBTarget sb_target = SBDebugger::GetCurrentTarget();
+ if (sb_target.IsValid())
+ {
+ SBProcess sb_process = sb_target.GetProcess();
+ if (sb_process.IsValid())
+ {
+ process = sb_process.get();
+ SBThread sb_thread = sb_process.GetCurrentThread();
+ if (sb_thread.IsValid())
+ {
+ thread = sb_thread.GetLLDBObjectPtr();
+ frame = thread->GetStackFrameAtIndex(0).get();
+ lldb_private::ExecutionContext exe_context (process, thread, frame);
+ return exe_context;
+ }
+ else
+ {
+ lldb_private::ExecutionContext exe_context (process, NULL, NULL);
+ return exe_context;
+ }
+ }
+ }
+
+ lldb_private::ExecutionContext exe_context (NULL, NULL, NULL);
+ return exe_context;
+}
+
+
+void *
+SBValue::GetOpaqueType()
+{
+ if (m_lldb_object_sp)
+ return m_lldb_object_sp->GetOpaqueClangQualType();
+ return NULL;
+}
+
+// Mimic shared pointer...
+lldb_private::ValueObject *
+SBValue::get() const
+{
+ return m_lldb_object_sp.get();
+}
+
+lldb_private::ValueObject *
+SBValue::operator->() const
+{
+ return m_lldb_object_sp.get();
+}
+
+lldb::ValueObjectSP &
+SBValue::operator*()
+{
+ return m_lldb_object_sp;
+}
+
+const lldb::ValueObjectSP &
+SBValue::operator*() const
+{
+ return m_lldb_object_sp;
+}
diff --git a/lldb/source/API/SBValueList.cpp b/lldb/source/API/SBValueList.cpp
new file mode 100644
index 00000000000..e7cbfad5308
--- /dev/null
+++ b/lldb/source/API/SBValueList.cpp
@@ -0,0 +1,140 @@
+//===-- 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/Core/ValueObjectList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBValueList::SBValueList () :
+ m_lldb_object_ap ()
+{
+}
+
+SBValueList::SBValueList (const SBValueList &rhs) :
+ m_lldb_object_ap ()
+{
+ if (rhs.IsValid())
+ m_lldb_object_ap.reset (new lldb_private::ValueObjectList (*rhs));
+}
+
+SBValueList::SBValueList (const lldb_private::ValueObjectList *lldb_object_ptr) :
+ m_lldb_object_ap ()
+{
+ if (lldb_object_ptr)
+ m_lldb_object_ap.reset (new lldb_private::ValueObjectList (*lldb_object_ptr));
+}
+
+SBValueList::~SBValueList ()
+{
+}
+
+bool
+SBValueList::IsValid () const
+{
+ return (m_lldb_object_ap.get() != NULL);
+}
+
+const SBValueList &
+SBValueList::operator = (const SBValueList &rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ m_lldb_object_ap.reset (new lldb_private::ValueObjectList (*rhs));
+ else
+ m_lldb_object_ap.reset ();
+ }
+ return *this;
+}
+
+lldb_private::ValueObjectList *
+SBValueList::operator->()
+{
+ return m_lldb_object_ap.get();
+}
+
+lldb_private::ValueObjectList &
+SBValueList::operator*()
+{
+ return *m_lldb_object_ap;
+}
+
+const lldb_private::ValueObjectList *
+SBValueList::operator->() const
+{
+ return m_lldb_object_ap.get();
+}
+
+const lldb_private::ValueObjectList &
+SBValueList::operator*() const
+{
+ return *m_lldb_object_ap;
+}
+
+void
+SBValueList::Append (const SBValue &val_obj)
+{
+ if (val_obj.get())
+ {
+ CreateIfNeeded ();
+ m_lldb_object_ap->Append (*val_obj);
+ }
+}
+
+void
+SBValueList::Append (lldb::ValueObjectSP& val_obj_sp)
+{
+ if (val_obj_sp)
+ {
+ CreateIfNeeded ();
+ m_lldb_object_ap->Append (val_obj_sp);
+ }
+}
+
+
+SBValue
+SBValueList::GetValueAtIndex (uint32_t idx) const
+{
+ SBValue sb_value;
+ if (m_lldb_object_ap.get())
+ *sb_value = m_lldb_object_ap->GetValueObjectAtIndex (idx);
+ return sb_value;
+}
+
+uint32_t
+SBValueList::GetSize () const
+{
+ uint32_t size = 0;
+ if (m_lldb_object_ap.get())
+ size = m_lldb_object_ap->GetSize();
+ return size;
+}
+
+void
+SBValueList::CreateIfNeeded ()
+{
+ if (m_lldb_object_ap.get() == NULL)
+ m_lldb_object_ap.reset (new ValueObjectList());
+}
+
+
+SBValue
+SBValueList::FindValueObjectByUID (lldb::user_id_t uid)
+{
+ SBValue sb_value;
+ if ( m_lldb_object_ap.get())
+ *sb_value = m_lldb_object_ap->FindValueObjectByUID (uid);
+ return sb_value;
+}
+
diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp
new file mode 100644
index 00000000000..c475cf0f0d7
--- /dev/null
+++ b/lldb/source/Breakpoint/Breakpoint.cpp
@@ -0,0 +1,516 @@
+//===-- 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/BreakpointResolver.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;
+using namespace lldb_private;
+
+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_target (target),
+ m_filter_sp (filter_sp),
+ m_resolver_sp (resolver_sp),
+ m_options (),
+ m_locations ()
+{
+}
+
+//----------------------------------------------------------------------
+// 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 (Address &addr, bool *new_location)
+{
+ BreakpointLocationSP bp_loc_sp (m_locations.FindByAddress(addr));
+ if (bp_loc_sp)
+ {
+ if (new_location)
+ *new_location = false;
+ return bp_loc_sp;
+ }
+
+ bp_loc_sp.reset (new BreakpointLocation (m_locations.GetNextID(), *this, addr));
+ m_locations.Add (bp_loc_sp);
+ bp_loc_sp->ResolveBreakpointSite();
+
+ if (new_location)
+ *new_location = true;
+ return bp_loc_sp;
+}
+
+BreakpointLocationSP
+Breakpoint::FindLocationByAddress (Address &addr)
+{
+ return m_locations.FindByAddress(addr);
+}
+
+break_id_t
+Breakpoint::FindLocationIDByAddress (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 (uint32_t index)
+{
+ return m_locations.GetByIndex(index);
+}
+
+BreakpointLocationSP
+Breakpoint::GetLocationSP (BreakpointLocation *bp_loc_ptr)
+{
+ assert (bp_loc_ptr->GetBreakpoint().GetID() == GetID());
+ return m_locations.FindByID(bp_loc_ptr->GetID());
+}
+
+
+// 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 vrs. 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)
+{
+ m_options.SetEnabled(enable);
+ if (enable)
+ m_locations.ResolveAllBreakpointSites();
+ else
+ m_locations.ClearAllBreakpointSites();
+}
+
+bool
+Breakpoint::IsEnabled ()
+{
+ return m_options.IsEnabled();
+}
+
+void
+Breakpoint::SetIgnoreCount (int32_t n)
+{
+ m_options.SetIgnoreCount(n);
+}
+
+int32_t
+Breakpoint::GetIgnoreCount () const
+{
+ return m_options.GetIgnoreCount();
+}
+
+void
+Breakpoint::SetThreadID (lldb::tid_t thread_id)
+{
+ m_options.SetThreadID(thread_id);
+}
+
+lldb::tid_t
+Breakpoint::GetThreadID ()
+{
+ return m_options.GetThreadID();
+}
+
+// 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);
+}
+
+// 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)
+{
+ 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.
+
+ for (int i = 0; i < module_list.GetSize(); i++)
+ {
+ bool seen = false;
+ ModuleSP module_sp (module_list.GetModuleAtIndex (i));
+ Module *module = module_sp.get();
+ if (!m_filter_sp->ModulePasses (module_sp))
+ continue;
+
+ for (int i = 0; i < m_locations.GetSize(); i++)
+ {
+ BreakpointLocationSP break_loc = m_locations.GetByIndex(i);
+ const Section *section = break_loc->GetAddress().GetSection();
+ if (section == NULL || section->GetModule() == module)
+ {
+ 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.AppendInNeeded (module_sp);
+
+ }
+ if (new_modules.GetSize() > 0)
+ {
+ ResolveBreakpointInModules(new_modules);
+ }
+ }
+ else
+ {
+ // Go through the currently set locations and if any have breakpoints in
+ // the module list, then remove their breakpoint sites.
+ // FIXME: Think about this... Maybe it's better to delete the locations?
+ // Are we sure that on load-unload-reload the module pointer will remain
+ // the same? Or do we need to do an equality on modules that is an
+ // "equivalence"???
+
+ for (int i = 0; i < module_list.GetSize(); i++)
+ {
+ ModuleSP module_sp (module_list.GetModuleAtIndex (i));
+ if (!m_filter_sp->ModulePasses (module_sp))
+ continue;
+
+ for (int i = 0; i < m_locations.GetSize(); i++)
+ {
+ BreakpointLocationSP break_loc = m_locations.GetByIndex(i);
+ const Section *section = break_loc->GetAddress().GetSection();
+ if (section)
+ {
+ if (section->GetModule() == module_sp.get())
+ break_loc->ClearBreakpointSite();
+ }
+// else
+// {
+// Address temp_addr;
+// if (module->ResolveLoadAddress(break_loc->GetLoadAddress(), m_target->GetProcess(), temp_addr))
+// break_loc->ClearBreakpointSite();
+// }
+ }
+ }
+ }
+}
+
+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);
+ StreamString filter_strm;
+
+
+ s->Printf("%i ", GetID());
+ GetResolverDescription (s);
+ GetFilterDescription (&filter_strm);
+ if (filter_strm.GetString().compare ("No Filter") != 0)
+ {
+ s->Printf (", ");
+ GetFilterDescription (s);
+ }
+
+ const uint32_t num_locations = GetNumLocations ();
+ const uint32_t num_resolved_locations = GetNumResolvedLocations ();
+
+ switch (level)
+ {
+ case lldb::eDescriptionLevelBrief:
+ case lldb::eDescriptionLevelFull:
+ if (num_locations > 0)
+ {
+ s->Printf(" with %u location%s", num_locations, num_locations > 1 ? "s" : "");
+ if (num_resolved_locations > 0)
+ s->Printf(" (%u resolved)", num_resolved_locations);
+ s->PutChar(';');
+ }
+ else
+ {
+ s->Printf(" with 0 locations (Pending Breakpoint).");
+ }
+
+ if (level == lldb::eDescriptionLevelFull)
+ {
+ Baton *baton = GetOptions()->GetBaton();
+ if (baton)
+ {
+ s->EOL ();
+ s->Indent();
+ baton->GetDescription(s, level);
+ }
+ }
+ break;
+
+ case lldb::eDescriptionLevelVerbose:
+ // Verbose mode does a debug dump of the breakpoint
+ Dump (s);
+ Baton *baton = GetOptions()->GetBaton();
+ if (baton)
+ {
+ s->EOL ();
+ s->Indent();
+ baton->GetDescription(s, level);
+ }
+ break;
+ }
+
+ if (show_locations)
+ {
+ s->EOL();
+ s->IndentMore();
+ for (int i = 0; i < GetNumLocations(); ++i)
+ {
+ BreakpointLocation *loc = GetLocationAtIndex(i).get();
+ loc->GetDescription(s, level);
+ s->EOL();
+ }
+ s->IndentLess();
+
+ }
+}
+
+Breakpoint::BreakpointEventData::BreakpointEventData (Breakpoint::BreakpointEventData::EventSubType sub_type, BreakpointSP &new_breakpoint_sp) :
+ EventData (),
+ m_sub_type (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;
+}
+
+Breakpoint::BreakpointEventData::EventSubType
+Breakpoint::BreakpointEventData::GetSubType () const
+{
+ return m_sub_type;
+}
+
+void
+Breakpoint::BreakpointEventData::Dump (Stream *s) const
+{
+}
+
+Breakpoint::BreakpointEventData *
+Breakpoint::BreakpointEventData::GetEventDataFromEvent (const EventSP &event_sp)
+{
+ if (event_sp)
+ {
+ EventData *event_data = event_sp->GetData();
+ if (event_data && event_data->GetFlavor() == BreakpointEventData::GetFlavorString())
+ return static_cast <BreakpointEventData *> (event_sp->GetData());
+ }
+ return NULL;
+}
+
+Breakpoint::BreakpointEventData::EventSubType
+Breakpoint::BreakpointEventData::GetSubTypeFromEvent (const EventSP &event_sp)
+{
+ BreakpointEventData *data = GetEventDataFromEvent (event_sp);
+
+ if (data == NULL)
+ return eBreakpointInvalidType;
+ else
+ return data->GetSubType();
+}
+
+BreakpointSP
+Breakpoint::BreakpointEventData::GetBreakpointFromEvent (const EventSP &event_sp)
+{
+ BreakpointEventData *data = GetEventDataFromEvent (event_sp);
+
+ if (data == NULL)
+ {
+ BreakpointSP ret_val;
+ return ret_val;
+ }
+ else
+ return data->GetBreakpoint();
+}
+
+
+void
+Breakpoint::GetResolverDescription (Stream *s)
+{
+ if (m_resolver_sp)
+ m_resolver_sp->GetDescription (s);
+}
+
+void
+Breakpoint::GetFilterDescription (Stream *s)
+{
+ m_filter_sp->GetDescription (s);
+}
+
+const BreakpointSP
+Breakpoint::GetSP ()
+{
+ return m_target.GetBreakpointList().FindBreakpointByID (GetID());
+}
diff --git a/lldb/source/Breakpoint/BreakpointID.cpp b/lldb/source/Breakpoint/BreakpointID.cpp
new file mode 100644
index 00000000000..691e5c07523
--- /dev/null
+++ b/lldb/source/Breakpoint/BreakpointID.cpp
@@ -0,0 +1,120 @@
+//===-- 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
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Breakpoint/BreakpointID.h"
+#include "lldb/Breakpoint/Breakpoint.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/lldb/source/Breakpoint/BreakpointIDList.cpp b/lldb/source/Breakpoint/BreakpointIDList.cpp
new file mode 100644
index 00000000000..895f1b1e3f4
--- /dev/null
+++ b/lldb/source/Breakpoint/BreakpointIDList.cpp
@@ -0,0 +1,348 @@
+//===-- 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/Core/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 ()
+{
+}
+
+int
+BreakpointIDList::Size()
+{
+ return m_breakpoint_ids.size();
+}
+
+BreakpointID &
+BreakpointIDList::GetBreakpointIDAtIndex (int index)
+{
+ if (index < m_breakpoint_ids.size())
+ return m_breakpoint_ids[index];
+ else
+ return m_invalid_id;
+}
+
+bool
+BreakpointIDList::RemoveBreakpointIDAtIndex (int index)
+{
+ bool success = false;
+ if (index < m_breakpoint_ids.size())
+ {
+ BreakpointIDArray::iterator pos;
+ int i;
+
+ for (pos = m_breakpoint_ids.begin(), i = 0; i != index && pos != m_breakpoint_ids.end(); ++pos, ++i);
+ assert (i == index);
+ if (pos != m_breakpoint_ids.end())
+ {
+ m_breakpoint_ids.erase (pos);
+ success = true;
+ }
+ }
+ return success;
+}
+
+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, int *position)
+{
+ bool success = false;
+ BreakpointIDArray::iterator tmp_pos;
+
+ for (int 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())
+ {
+ success = true;
+ *position = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+BreakpointIDList::FindBreakpointID (const char *bp_id_str, int *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, int array_size, CommandReturnObject &result)
+{
+ if (string_array == NULL)
+ return;
+
+ for (int 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)
+{
+ char *range_start;
+ const char *range_end;
+ const char *current_arg;
+ int num_old_args = old_args.GetArgumentCount();
+
+ for (int i = 0; i < num_old_args; ++i)
+ {
+ bool is_range = false;
+ current_arg = old_args.GetArgumentAtIndex (i);
+
+ int range_start_len = 0;
+ int range_end_pos = 0;
+ if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos))
+ {
+ is_range = true;
+ range_start = (char *) malloc (range_start_len + 1);
+ strncpy (range_start, current_arg, range_start_len);
+ range_start[range_start_len] = '\0';
+ 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 = (char *) current_arg;
+ range_end = old_args.GetArgumentAtIndex (i+2);
+ is_range = true;
+ i = i+2;
+ }
+
+ 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, &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);
+ 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;
+ }
+
+ // 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.
+
+ const BreakpointList& breakpoints = target->GetBreakpointList();
+ size_t num_breakpoints = breakpoints.GetSize();
+ for (int j = 0; j < num_breakpoints; ++j)
+ {
+ Breakpoint *breakpoint = breakpoints.GetBreakpointByIndex (j).get();
+ break_id_t cur_bp_id = breakpoint->GetID();
+
+ if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
+ continue;
+
+ size_t num_locations = breakpoint->GetNumLocations();
+
+ if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID))
+ {
+ for (int k = 0; k < num_locations; ++k)
+ {
+ BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
+ if (bp_loc->GetID() >= start_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 (int 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, const char **range_start,
+// const **range_end)
+bool
+BreakpointIDList::StringContainsIDRangeExpression (const char *in_string, int *range_start_len, int *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 = NULL;
+ //*range_end = NULL;
+ *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];
+ int 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/lldb/source/Breakpoint/BreakpointList.cpp b/lldb/source/Breakpoint/BreakpointList.cpp
new file mode 100644
index 00000000000..c10aa770b82
--- /dev/null
+++ b/lldb/source/Breakpoint/BreakpointList.cpp
@@ -0,0 +1,198 @@
+//===-- 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
+
+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)
+{
+ Mutex::Locker locker(m_mutex);
+ // Internal breakpoint IDs are negative, normal ones are positive
+ bp->SetID (m_is_internal ? --m_next_break_id : ++m_next_break_id);
+ m_breakpoints.push_back(bp);
+ return bp->GetID();
+}
+
+bool
+BreakpointList::Remove (break_id_t break_id)
+{
+ Mutex::Locker locker(m_mutex);
+ bp_collection::iterator pos = GetBreakpointIDIterator(break_id); // Predicate
+ if (pos != m_breakpoints.end())
+ {
+ m_breakpoints.erase(pos);
+ 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 ()
+{
+ Mutex::Locker locker(m_mutex);
+ ClearAllBreakpointSites ();
+
+ 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: ", (int)sizeof(void*) * 2, 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::GetBreakpointByIndex (uint32_t i)
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSP stop_sp;
+ bp_collection::iterator end = m_breakpoints.end();
+ bp_collection::iterator pos;
+ uint32_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::GetBreakpointByIndex (uint32_t i) const
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSP stop_sp;
+ bp_collection::const_iterator end = m_breakpoints.end();
+ bp_collection::const_iterator pos;
+ uint32_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::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 ();
+
+}
diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp
new file mode 100644
index 00000000000..5c0e81df381
--- /dev/null
+++ b/lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -0,0 +1,389 @@
+//===-- BreakpointLocation.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 <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointID.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointLocation::BreakpointLocation
+(
+ break_id_t loc_id,
+ Breakpoint &owner,
+ Address &addr,
+ lldb::tid_t tid,
+ bool hardware
+) :
+ StoppointLocation (loc_id, addr.GetLoadAddress(owner.GetTarget().GetProcessSP().get()), tid, hardware),
+ m_address (addr),
+ m_owner (owner),
+ m_options_ap (),
+ m_bp_site_sp ()
+{
+}
+
+BreakpointLocation::~BreakpointLocation()
+{
+ ClearBreakpointSite();
+}
+
+lldb::addr_t
+BreakpointLocation::GetLoadAddress ()
+{
+ return m_address.GetLoadAddress(m_owner.GetTarget().GetProcessSP().get());
+}
+
+Address &
+BreakpointLocation::GetAddress ()
+{
+ return m_address;
+}
+
+Breakpoint &
+BreakpointLocation::GetBreakpoint ()
+{
+ return m_owner;
+}
+
+bool
+BreakpointLocation::IsEnabled ()
+{
+ 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();
+ }
+}
+
+void
+BreakpointLocation::SetThreadID (lldb::tid_t thread_id)
+{
+ GetLocationOptions()->SetThreadID(thread_id);
+}
+
+lldb::tid_t
+BreakpointLocation::GetThreadID ()
+{
+ return GetOptionsNoCopy()->GetThreadID();
+}
+
+bool
+BreakpointLocation::InvokeCallback (StoppointCallbackContext *context)
+{
+ bool owner_result;
+
+ owner_result = m_owner.InvokeCallback (context, GetID());
+ if (owner_result == false)
+ return false;
+ else if (m_options_ap.get() != NULL)
+ return m_options_ap->InvokeCallback (context, m_owner.GetID(), GetID());
+ else
+ return true;
+}
+
+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);
+}
+
+void
+BreakpointLocation::SetCallback (BreakpointHitCallback callback, const BatonSP &baton_sp,
+ bool is_synchronous)
+{
+ GetLocationOptions()->SetCallback (callback, baton_sp, is_synchronous);
+}
+
+void
+BreakpointLocation::ClearCallback ()
+{
+ GetLocationOptions()->ClearCallback();
+}
+
+int32_t
+BreakpointLocation::GetIgnoreCount ()
+{
+ return GetOptionsNoCopy()->GetIgnoreCount();
+}
+
+void
+BreakpointLocation::SetIgnoreCount (int32_t n)
+{
+ GetLocationOptions()->SetIgnoreCount(n);
+}
+
+BreakpointOptions *
+BreakpointLocation::GetOptionsNoCopy ()
+{
+ if (m_options_ap.get() != NULL)
+ return m_options_ap.get();
+ else
+ return m_owner.GetOptions ();
+}
+
+BreakpointOptions *
+BreakpointLocation::GetLocationOptions ()
+{
+ if (m_options_ap.get() == NULL)
+ m_options_ap.reset(new BreakpointOptions (*m_owner.GetOptions ()));
+
+ return m_options_ap.get();
+}
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue.
+
+bool
+BreakpointLocation::ShouldStop (StoppointCallbackContext *context)
+{
+ bool should_stop = true;
+
+ m_hit_count++;
+
+ if (!IsEnabled())
+ return false;
+
+ if (GetThreadID() != LLDB_INVALID_THREAD_ID
+ && context->context.thread->GetID() != GetThreadID())
+ return false;
+
+ if (m_hit_count <= GetIgnoreCount())
+ return false;
+
+ // Tell if the callback is synchronous here.
+ context->is_synchronous = true;
+ should_stop = InvokeCallback (context);
+
+ if (should_stop)
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ if (log)
+ {
+ StreamString s;
+ GetDescription (&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Hit breakpoint location: %s\n", s.GetData());
+ }
+ }
+ return should_stop;
+}
+
+bool
+BreakpointLocation::IsResolved () const
+{
+ return m_bp_site_sp.get() != NULL;
+}
+
+bool
+BreakpointLocation::ResolveBreakpointSite ()
+{
+ if (m_bp_site_sp)
+ return true;
+
+ Process* process = m_owner.GetTarget().GetProcessSP().get();
+ if (process == NULL)
+ return false;
+
+ BreakpointLocationSP myself_sp(m_owner.GetLocationSP (this));
+
+ lldb::user_id_t new_id = process->CreateBreakpointSite (myself_sp, false);
+
+ if (new_id == LLDB_INVALID_UID)
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ if (log)
+ log->Warning ("Tried to add breakpoint site at 0x%llx but it was already present.\n",
+ m_address.GetLoadAddress(process));
+ 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;
+ s->Indent();
+ BreakpointID::GetCanonicalReference(s, m_owner.GetID(), GetID());
+
+ if (level == lldb::eDescriptionLevelBrief)
+ return;
+
+ s->PutCString(": ");
+
+ if (level == lldb::eDescriptionLevelVerbose)
+ s->IndentMore();
+
+ if (m_address.IsSectionOffset())
+ {
+ m_address.CalculateSymbolContext(&sc);
+
+ if (level == lldb::eDescriptionLevelFull)
+ {
+ s->PutCString("where = ");
+ sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address);
+ }
+ 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 = ");
+ dynamic_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);
+ }
+
+ }
+ 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();
+ }
+ s->Printf ("%saddress = ", (level == lldb::eDescriptionLevelFull && m_address.IsSectionOffset()) ? ", " : "");
+ ExecutionContextScope *exe_scope = NULL;
+ Target *target = &m_owner.GetTarget();
+ if (target)
+ exe_scope = target->GetProcessSP().get();
+ if (exe_scope == NULL)
+ exe_scope = target;
+
+ 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("enabled = %s\n", IsEnabled() ? "true" : "false");
+
+ s->Indent();
+ s->Printf ("hit count = %-4u\n", GetHitCount());
+
+ if (m_options_ap.get())
+ {
+ Baton *baton = m_options_ap->GetBaton();
+ if (baton)
+ {
+ s->Indent();
+ baton->GetDescription (s, level);
+ s->EOL();
+ }
+ }
+ s->IndentLess();
+ }
+ else
+ {
+ s->Printf(", %sresolved, %s, hit count = %u",
+ (IsResolved() ? "" : "un"),
+ (IsEnabled() ? "enabled" : "disabled"),
+ GetHitCount());
+ }
+}
+
+void
+BreakpointLocation::Dump(Stream *s) const
+{
+ if (s == NULL)
+ return;
+
+ s->Printf("BreakpointLocation %u: tid = %4.4x load addr = 0x%8.8llx state = %s type = %s breakpoint hw_index = %i hit_count = %-4u ignore_count = %-4u",
+ GetID(),
+ m_tid,
+ (uint64_t) m_address.GetLoadAddress(m_owner.GetTarget().GetProcessSP().get()),
+ (m_options_ap.get() ? m_options_ap->IsEnabled() : m_owner.IsEnabled()) ? "enabled " : "disabled",
+ IsHardware() ? "hardware" : "software",
+ GetHardwareIndex(),
+ GetHitCount(),
+ m_options_ap.get() ? m_options_ap->GetIgnoreCount() : m_owner.GetIgnoreCount());
+}
diff --git a/lldb/source/Breakpoint/BreakpointLocationCollection.cpp b/lldb/source/Breakpoint/BreakpointLocationCollection.cpp
new file mode 100644
index 00000000000..7b574263003
--- /dev/null
+++ b/lldb/source/Breakpoint/BreakpointLocationCollection.cpp
@@ -0,0 +1,161 @@
+//===-- 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/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointLocationList.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::user_id_t bp_id, lldb::user_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::user_id_t break_id, lldb::user_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::user_id_t m_break_id;
+ const lldb::user_id_t m_break_loc_id;
+};
+
+BreakpointLocationCollection::collection::iterator
+BreakpointLocationCollection::GetIDPairIterator (lldb::user_id_t break_id, lldb::user_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::user_id_t break_id, lldb::user_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::user_id_t break_id, lldb::user_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::user_id_t break_id, lldb::user_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 (uint32_t i)
+{
+ BreakpointLocationSP stop_sp;
+ if (i >= 0 && i < m_break_loc_collection.size())
+ stop_sp = m_break_loc_collection[i];
+
+ return stop_sp;
+}
+
+const BreakpointLocationSP
+BreakpointLocationCollection::GetByIndex (uint32_t i) const
+{
+ BreakpointLocationSP stop_sp;
+ if (i >= 0 && i < m_break_loc_collection.size())
+ stop_sp = m_break_loc_collection[i];
+
+ return stop_sp;
+}
+
+bool
+BreakpointLocationCollection::ShouldStop (StoppointCallbackContext *context)
+{
+ bool shouldStop = false;
+
+ for (int i = 0; i < GetSize(); i++) {
+ bool one_result = GetByIndex(i)->ShouldStop(context);
+ if (one_result)
+ shouldStop = true;
+ }
+ return shouldStop;
+}
+
+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/lldb/source/Breakpoint/BreakpointLocationList.cpp b/lldb/source/Breakpoint/BreakpointLocationList.cpp
new file mode 100644
index 00000000000..d86a8cf4c47
--- /dev/null
+++ b/lldb/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/Core/ModuleList.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointLocationList::BreakpointLocationList() :
+ m_locations(),
+ m_address_to_location (),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_next_id (0)
+{
+}
+
+BreakpointLocationList::~BreakpointLocationList()
+{
+}
+
+lldb::user_id_t
+BreakpointLocationList::Add (BreakpointLocationSP &bp_loc_sp)
+{
+ if (bp_loc_sp)
+ {
+ Mutex::Locker locker (m_mutex);
+ m_locations.push_back (bp_loc_sp);
+ m_address_to_location[bp_loc_sp->GetAddress()] = bp_loc_sp;
+ return bp_loc_sp->GetID();
+ }
+ return LLDB_INVALID_BREAK_ID;
+}
+
+bool
+BreakpointLocationList::ShouldStop (StoppointCallbackContext *context, lldb::user_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::user_id_t
+BreakpointLocationList::FindIDByAddress (Address &addr)
+{
+ BreakpointLocationSP bp_loc_sp = FindByAddress (addr);
+ if (bp_loc_sp)
+ {
+ return bp_loc_sp->GetID();
+ }
+ return LLDB_INVALID_BREAK_ID;
+}
+
+bool
+BreakpointLocationList::Remove (lldb::user_id_t break_id)
+{
+ Mutex::Locker locker (m_mutex);
+ collection::iterator pos = GetIDIterator(break_id); // Predicate
+ if (pos != m_locations.end())
+ {
+ m_address_to_location.erase ((*pos)->GetAddress());
+ m_locations.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+
+class BreakpointLocationIDMatches
+{
+public:
+ BreakpointLocationIDMatches (lldb::user_id_t break_id) :
+ m_break_id(break_id)
+ {
+ }
+
+ bool operator() (const BreakpointLocationSP &bp_loc_sp) const
+ {
+ return m_break_id == bp_loc_sp->GetID();
+ }
+
+private:
+ const lldb::user_id_t m_break_id;
+};
+
+class BreakpointLocationAddressMatches
+{
+public:
+ BreakpointLocationAddressMatches (Address& addr) :
+ m_addr(addr)
+ {
+ }
+
+ bool operator() (const BreakpointLocationSP& bp_loc_sp) const
+ {
+ return Address::CompareFileAddress(m_addr, bp_loc_sp->GetAddress()) == 0;
+ }
+
+private:
+ const Address &m_addr;
+};
+
+BreakpointLocationList::collection::iterator
+BreakpointLocationList::GetIDIterator (lldb::user_id_t break_id)
+{
+ Mutex::Locker locker (m_mutex);
+ return std::find_if (m_locations.begin(),
+ m_locations.end(),
+ BreakpointLocationIDMatches(break_id));
+}
+
+BreakpointLocationList::collection::const_iterator
+BreakpointLocationList::GetIDConstIterator (lldb::user_id_t break_id) const
+{
+ Mutex::Locker locker (m_mutex);
+ return std::find_if (m_locations.begin(),
+ m_locations.end(),
+ BreakpointLocationIDMatches(break_id));
+}
+
+BreakpointLocationSP
+BreakpointLocationList::FindByID (lldb::user_id_t break_id)
+{
+ Mutex::Locker locker (m_mutex);
+ BreakpointLocationSP stop_sp;
+ collection::iterator pos = GetIDIterator(break_id);
+ if (pos != m_locations.end())
+ stop_sp = *pos;
+
+ return stop_sp;
+}
+
+const BreakpointLocationSP
+BreakpointLocationList::FindByID (lldb::user_id_t break_id) const
+{
+ Mutex::Locker locker (m_mutex);
+ BreakpointLocationSP stop_sp;
+ collection::const_iterator pos = GetIDConstIterator(break_id);
+ if (pos != m_locations.end())
+ stop_sp = *pos;
+
+ return stop_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)
+ {
+ bool seen = false;
+ BreakpointLocationSP break_loc = (*pos);
+ const Section *section = break_loc->GetAddress().GetSection();
+ if (section)
+ {
+ if (section->GetModule() == module)
+ {
+ if (!seen)
+ {
+ seen = true;
+ bp_loc_list.Add (break_loc);
+ }
+
+ }
+ }
+ }
+ return bp_loc_list.GetSize() - orig_size;
+}
+
+
+static int
+FindLocationByAddress (Address *addr_ptr, const BreakpointLocationSP *bp_loc_sp_ptr)
+{
+ return Address::CompareModulePointerAndOffset(*addr_ptr, (*bp_loc_sp_ptr)->GetAddress());
+}
+
+const BreakpointLocationSP
+BreakpointLocationList::FindByAddress (Address &addr) const
+{
+ Mutex::Locker locker (m_mutex);
+ BreakpointLocationSP stop_sp;
+ if (!m_locations.empty())
+ {
+ addr_map::const_iterator pos = m_address_to_location.find (addr);
+ if (pos != m_address_to_location.end())
+ stop_sp = pos->second;
+ }
+
+ return stop_sp;
+}
+
+void
+BreakpointLocationList::Dump (Stream *s) const
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ Mutex::Locker locker (m_mutex);
+ s->Printf("BreakpointLocationList with %zu BreakpointLocations:\n", 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 (uint32_t i)
+{
+ Mutex::Locker locker (m_mutex);
+ BreakpointLocationSP stop_sp;
+ if (i >= 0 && i < m_locations.size())
+ stop_sp = m_locations[i];
+
+ return stop_sp;
+}
+
+const BreakpointLocationSP
+BreakpointLocationList::GetByIndex (uint32_t i) const
+{
+ Mutex::Locker locker (m_mutex);
+ BreakpointLocationSP stop_sp;
+ if (i >= 0 && i < m_locations.size())
+ stop_sp = m_locations[i];
+
+ return stop_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)
+ (*pos)->ResolveBreakpointSite();
+}
+
+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;
+}
+
+break_id_t
+BreakpointLocationList::GetNextID()
+{
+ return ++m_next_id;
+}
+
+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);
+ }
+}
+
diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp
new file mode 100644
index 00000000000..4f664c4692f
--- /dev/null
+++ b/lldb/source/Breakpoint/BreakpointOptions.cpp
@@ -0,0 +1,180 @@
+//===-- 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/Breakpoint/StoppointCallbackContext.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_is_synchronous (false),
+ m_callback_baton_sp (),
+ m_enabled (true),
+ m_ignore_count (0),
+ m_thread_id (LLDB_INVALID_THREAD_ID)
+{
+}
+
+//----------------------------------------------------------------------
+// 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_ignore_count (rhs.m_ignore_count),
+ m_thread_id (rhs.m_thread_id)
+{
+}
+
+//----------------------------------------------------------------------
+// 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_ignore_count = rhs.m_ignore_count;
+ m_thread_id = rhs.m_thread_id;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// 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 = NULL;
+ m_callback_baton_sp.reset();
+}
+
+Baton *
+BreakpointOptions::GetBaton ()
+{
+ 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;
+}
+
+//------------------------------------------------------------------
+// Enabled/Ignore Count
+//------------------------------------------------------------------
+bool
+BreakpointOptions::IsEnabled () const
+{
+ return m_enabled;
+}
+
+void
+BreakpointOptions::SetEnabled (bool enabled)
+{
+ m_enabled = enabled;
+}
+
+int32_t
+BreakpointOptions::GetIgnoreCount () const
+{
+ return m_ignore_count;
+}
+
+void
+BreakpointOptions::SetIgnoreCount (int32_t n)
+{
+ m_ignore_count = n;
+}
+
+void
+BreakpointOptions::SetThreadID (lldb::tid_t thread_id)
+{
+ m_thread_id = thread_id;
+}
+
+lldb::tid_t
+BreakpointOptions::GetThreadID () const
+{
+ return m_thread_id;
+}
+
+
+
+void
+BreakpointOptions::CommandBaton::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ s->Indent("Breakpoint commands:\n");
+ CommandData *data = (CommandData *)m_data;
+
+ 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 ();
+}
+
diff --git a/lldb/source/Breakpoint/BreakpointResolver.cpp b/lldb/source/Breakpoint/BreakpointResolver.cpp
new file mode 100644
index 00000000000..e0fbfde7932
--- /dev/null
+++ b/lldb/source/Breakpoint/BreakpointResolver.cpp
@@ -0,0 +1,60 @@
+//===-- 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) :
+ m_breakpoint (bkpt)
+{
+}
+
+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/lldb/source/Breakpoint/BreakpointResolverAddress.cpp b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp
new file mode 100644
index 00000000000..034ef601dc4
--- /dev/null
+++ b/lldb/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),
+ 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 breakpoint: ");
+ m_addr.Dump(s, m_breakpoint->GetTarget().GetProcessSP().get(), Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
+}
+
+void
+BreakpointResolverAddress::Dump (Stream *s) const
+{
+
+}
diff --git a/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp b/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
new file mode 100644
index 00000000000..86e05964485
--- /dev/null
+++ b/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
@@ -0,0 +1,122 @@
+//===-- 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/StreamString.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
+) :
+ BreakpointResolver (bkpt),
+ m_file_spec (file_spec),
+ m_line_number (line_no),
+ m_inlines (check_inlines)
+{
+}
+
+BreakpointResolverFileLine::~BreakpointResolverFileLine ()
+{
+}
+
+Searcher::CallbackReturn
+BreakpointResolverFileLine::SearchCallback
+(
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing
+)
+{
+ SymbolContextList sc_list;
+ uint32_t sc_list_size;
+ CompileUnit *cu = context.comp_unit;
+
+ assert (m_breakpoint != NULL);
+ 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 (int i = 0; i < sc_list_size; i++)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ Address line_start = sc.line_entry.range.GetBaseAddress();
+ if (line_start.IsValid())
+ {
+ 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 ("error: Unable to set breakpoint at file address 0x%llx for %s:%d\n",
+ line_start.GetFileAddress(),
+ m_file_spec.GetFilename().AsCString("<Unknown>"),
+ m_line_number);
+ }
+ }
+ else
+ {
+#if 0
+ s << "error: Breakpoint at '" << pos->c_str() << "' isn't resolved yet: \n";
+ if (sc.line_entry.address.Dump(&s, Address::DumpStyleSectionNameOffset))
+ s.EOL();
+ if (sc.line_entry.address.Dump(&s, Address::DumpStyleSectionPointerOffset))
+ s.EOL();
+ if (sc.line_entry.address.Dump(&s, Address::DumpStyleFileAddress))
+ s.EOL();
+ if (sc.line_entry.address.Dump(&s, Address::DumpStyleLoadAddress))
+ s.EOL();
+#endif
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::Depth
+BreakpointResolverFileLine::GetDepth()
+{
+ return Searcher::eDepthCompUnit;
+}
+
+void
+BreakpointResolverFileLine::GetDescription (Stream *s)
+{
+ s->Printf ("File and line breakpoint - file: \"%s\" line: %u", m_file_spec.GetFilename().AsCString(), m_line_number);
+}
+
+void
+BreakpointResolverFileLine::Dump (Stream *s) const
+{
+
+}
+
diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp
new file mode 100644
index 00000000000..b04bb8aef48
--- /dev/null
+++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp
@@ -0,0 +1,252 @@
+//===-- 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/StreamString.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointResolverName::BreakpointResolverName
+(
+ Breakpoint *bkpt,
+ const char *func_name,
+ Breakpoint::MatchType type
+) :
+ BreakpointResolver (bkpt),
+ m_func_name (func_name),
+ m_class_name (NULL),
+ m_regex (),
+ m_match_type (type)
+{
+ if (m_match_type == Breakpoint::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());
+ }
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName
+(
+ Breakpoint *bkpt,
+ RegularExpression &func_regex
+) :
+ BreakpointResolver (bkpt),
+ m_func_name (NULL),
+ m_class_name (NULL),
+ m_regex (func_regex),
+ m_match_type (Breakpoint::Regexp)
+{
+
+}
+
+BreakpointResolverName::BreakpointResolverName
+(
+ Breakpoint *bkpt,
+ const char *class_name,
+ const char *method,
+ Breakpoint::MatchType type
+) :
+ BreakpointResolver (bkpt),
+ m_func_name (method),
+ m_class_name (class_name),
+ m_regex (),
+ m_match_type (type)
+{
+
+}
+
+BreakpointResolverName::~BreakpointResolverName ()
+{
+}
+
+// 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;
+
+ bool skip_prologue = true;
+ uint32_t i;
+ bool new_location;
+ SymbolContext sc;
+ 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;
+ }
+
+ switch (m_match_type)
+ {
+ case Breakpoint::Exact:
+ if (context.module_sp)
+ {
+ context.module_sp->FindSymbolsWithNameAndType (m_func_name, eSymbolTypeCode, sym_list);
+ context.module_sp->FindFunctions (m_func_name, false, func_list);
+ }
+ break;
+ case Breakpoint::Regexp:
+ if (context.module_sp)
+ {
+ context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, eSymbolTypeCode, sym_list);
+ context.module_sp->FindFunctions (m_regex, true, func_list);
+ }
+ break;
+ case Breakpoint::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->GetAddressRangePtr())
+ {
+ if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRangePtr()->GetBaseAddress())
+ {
+ 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)
+ {
+ break_addr = sc.function->GetAddressRange().GetBaseAddress();
+ if (skip_prologue)
+ {
+ const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
+ if (prologue_byte_size)
+ break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
+ }
+
+ 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());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < sym_list.GetSize(); i++)
+ {
+ if (sym_list.GetContextAtIndex(i, sc))
+ {
+ if (sc.symbol && sc.symbol->GetAddressRangePtr())
+ {
+ break_addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress();
+
+ if (skip_prologue)
+ {
+ const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
+ if (prologue_byte_size)
+ break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
+ }
+
+ 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())
+ {
+ StreamString s;
+ bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ if (log)
+ log->Printf ("Added location: %s\n", s.GetData());
+ }
+ }
+ }
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::Depth
+BreakpointResolverName::GetDepth()
+{
+ return Searcher::eDepthModule;
+}
+
+void
+BreakpointResolverName::GetDescription (Stream *s)
+{
+ s->PutCString("Breakpoint by name: ");
+
+ if (m_match_type == Breakpoint::Regexp)
+ s->Printf("'%s' (regular expression)", m_regex.GetText());
+ else
+ s->Printf("'%s'", m_func_name.AsCString());
+}
+
+void
+BreakpointResolverName::Dump (Stream *s) const
+{
+
+}
+
diff --git a/lldb/source/Breakpoint/BreakpointSite.cpp b/lldb/source/Breakpoint/BreakpointSite.cpp
new file mode 100644
index 00000000000..cd0920d07c7
--- /dev/null
+++ b/lldb/source/Breakpoint/BreakpointSite.cpp
@@ -0,0 +1,221 @@
+//===-- 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/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointSiteList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointSite::BreakpointSite
+(
+ BreakpointSiteList *list,
+ BreakpointLocationSP& owner,
+ lldb::addr_t addr,
+ lldb::tid_t tid,
+ bool use_hardware
+) :
+ StoppointLocation(GetNextID(), addr, tid, 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;
+ for (int i = 0; i < m_owners.GetSize(); 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)
+{
+ m_hit_count++;
+ return m_owners.ShouldStop (context);
+}
+
+bool
+BreakpointSite::IsBreakpointAtThisSite (lldb::break_id_t bp_id)
+{
+ for (int i = 0; i < m_owners.GetSize(); 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: tid = %4.4x addr = 0x%8.8llx type = %s breakpoint hw_index = %i hit_count = %-4u",
+ GetID(),
+ m_tid,
+ (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 ", GetID());
+ m_owners.GetDescription (s, level);
+}
+
+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, size_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 (BreakpointLocationSP &owner)
+{
+ m_owners.Add(owner);
+}
+
+uint32_t
+BreakpointSite::RemoveOwner (lldb::user_id_t break_id, lldb::user_id_t break_loc_id)
+{
+ m_owners.Remove(break_id, break_loc_id);
+ return m_owners.GetSize();
+}
+
+uint32_t
+BreakpointSite::GetNumberOfOwners ()
+{
+ return m_owners.GetSize();
+}
+
+BreakpointLocationSP
+BreakpointSite::GetOwnerAtIndex (uint32_t index)
+{
+ return m_owners.GetByIndex (index);
+}
+
+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/lldb/source/Breakpoint/BreakpointSiteList.cpp b/lldb/source/Breakpoint/BreakpointSiteList.cpp
new file mode 100644
index 00000000000..19e18bb749a
--- /dev/null
+++ b/lldb/source/Breakpoint/BreakpointSiteList.cpp
@@ -0,0 +1,229 @@
+//===-- 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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointSiteList::BreakpointSiteList() :
+ 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::user_id_t
+BreakpointSiteList::Add(const BreakpointSiteSP &bp)
+{
+ lldb::addr_t bp_site_load_addr = bp->GetLoadAddress();
+ 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::user_id_t break_id)
+{
+ BreakpointSiteSP bp = FindByID (break_id);
+ if (bp)
+ {
+ // 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 bp->ShouldStop (context);
+ }
+ // We should stop here since this BreakpointSite isn't valid anymore or it
+ // doesn't exist.
+ return true;
+}
+lldb::user_id_t
+BreakpointSiteList::FindIDByAddress (lldb::addr_t addr)
+{
+ BreakpointSiteSP bp = FindByAddress (addr);
+ if (bp)
+ {
+ //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8llx ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID());
+ return bp.get()->GetID();
+ }
+ //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8llx ) => NONE", __FUNCTION__, (uint64_t)addr);
+ return LLDB_INVALID_BREAK_ID;
+}
+
+bool
+BreakpointSiteList::Remove (lldb::user_id_t break_id)
+{
+ 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)
+{
+ 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::user_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::user_id_t m_break_id;
+};
+
+BreakpointSiteList::collection::iterator
+BreakpointSiteList::GetIDIterator (lldb::user_id_t break_id)
+{
+ 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::user_id_t break_id) const
+{
+ 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::user_id_t break_id)
+{
+ 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::user_id_t break_id) const
+{
+ 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;
+
+ collection::iterator iter = m_bp_site_list.find(addr);
+ if (iter != m_bp_site_list.end())
+ found_sp = iter->second;
+ return found_sp;
+}
+
+void
+BreakpointSiteList::Dump (Stream *s) const
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, 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();
+}
+
+
+BreakpointSiteSP
+BreakpointSiteList::GetByIndex (uint32_t i)
+{
+ BreakpointSiteSP stop_sp;
+ collection::iterator end = m_bp_site_list.end();
+ collection::iterator pos;
+ uint32_t curr_i = 0;
+ for (pos = m_bp_site_list.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
+ {
+ if (curr_i == i)
+ stop_sp = pos->second;
+ }
+ return stop_sp;
+}
+
+const BreakpointSiteSP
+BreakpointSiteList::GetByIndex (uint32_t i) const
+{
+ BreakpointSiteSP stop_sp;
+ collection::const_iterator end = m_bp_site_list.end();
+ collection::const_iterator pos;
+ uint32_t curr_i = 0;
+ for (pos = m_bp_site_list.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
+ {
+ if (curr_i == i)
+ stop_sp = pos->second;
+ }
+ return stop_sp;
+}
+
+void
+BreakpointSiteList::SetEnabledForAll (const bool enabled, const lldb::user_id_t except_id)
+{
+ collection::iterator end = m_bp_site_list.end();
+ collection::iterator pos;
+ for (pos = m_bp_site_list.begin(); pos != end; ++pos)
+ {
+ if (except_id != LLDB_INVALID_BREAK_ID && except_id != pos->second->GetID())
+ pos->second->SetEnabled (enabled);
+ else
+ pos->second->SetEnabled (!enabled);
+ }
+}
+
+const BreakpointSiteList::collection *
+BreakpointSiteList::GetMap ()
+{
+ return &m_bp_site_list;
+}
diff --git a/lldb/source/Breakpoint/Stoppoint.cpp b/lldb/source/Breakpoint/Stoppoint.cpp
new file mode 100644
index 00000000000..583ab47005f
--- /dev/null
+++ b/lldb/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/lldb/source/Breakpoint/StoppointCallbackContext.cpp b/lldb/source/Breakpoint/StoppointCallbackContext.cpp
new file mode 100644
index 00000000000..86620621c76
--- /dev/null
+++ b/lldb/source/Breakpoint/StoppointCallbackContext.cpp
@@ -0,0 +1,38 @@
+//===-- 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),
+ context()
+{
+}
+
+StoppointCallbackContext::StoppointCallbackContext(Event *e, Process* p, Thread *t, StackFrame *f, bool synchronously) :
+ event (e),
+ context (p, t, f),
+ is_synchronous(synchronously)
+{
+}
+
+void
+StoppointCallbackContext::Clear()
+{
+ event = NULL;
+ context.Clear();
+ is_synchronous = false;
+}
diff --git a/lldb/source/Breakpoint/StoppointLocation.cpp b/lldb/source/Breakpoint/StoppointLocation.cpp
new file mode 100644
index 00000000000..999ad536ab8
--- /dev/null
+++ b/lldb/source/Breakpoint/StoppointLocation.cpp
@@ -0,0 +1,120 @@
+//===-- 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, tid_t tid, bool hardware) :
+ m_loc_id(bid),
+ m_tid(tid),
+ m_byte_size(0),
+ m_addr(addr),
+ m_hit_count(0),
+ m_hw_preferred(hardware),
+ m_hw_index(LLDB_INVALID_INDEX32)
+{
+}
+
+StoppointLocation::StoppointLocation (break_id_t bid, addr_t addr, tid_t tid, size_t size, bool hardware) :
+ m_loc_id(bid),
+ m_tid(tid),
+ m_byte_size(size),
+ m_addr(addr),
+ m_hit_count(0),
+ m_hw_preferred(hardware),
+ m_hw_index(LLDB_INVALID_INDEX32)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StoppointLocation::~StoppointLocation()
+{
+}
+
+
+size_t
+StoppointLocation::GetByteSize () const
+{
+ return m_byte_size;
+}
+
+addr_t
+StoppointLocation::GetLoadAddress() const
+{
+ return m_addr;
+}
+
+tid_t
+StoppointLocation::GetThreadID() const
+{
+ return m_tid;
+}
+
+uint32_t
+StoppointLocation::GetHitCount () const
+{
+ return m_hit_count;
+}
+
+bool
+StoppointLocation::HardwarePreferred () const
+{
+ return m_hw_preferred;
+}
+
+bool
+StoppointLocation::IsHardware () const
+{
+ return m_hw_index != LLDB_INVALID_INDEX32;
+}
+
+uint32_t
+StoppointLocation::GetHardwareIndex () const
+{
+ return m_hw_index;
+}
+
+void
+StoppointLocation::SetHardwareIndex (uint32_t hw_index)
+{
+ m_hw_index = hw_index;
+}
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue.
+
+bool
+StoppointLocation::ShouldStop (StoppointCallbackContext *context)
+{
+ return true;
+}
+
+break_id_t
+StoppointLocation::GetID() const
+{
+ return m_loc_id;
+}
+
+void
+StoppointLocation::Dump (Stream *stream) const
+{
+
+}
diff --git a/lldb/source/Breakpoint/WatchpointLocation.cpp b/lldb/source/Breakpoint/WatchpointLocation.cpp
new file mode 100644
index 00000000000..f765ef43202
--- /dev/null
+++ b/lldb/source/Breakpoint/WatchpointLocation.cpp
@@ -0,0 +1,137 @@
+//===-- WatchpointLocation.cpp ----------------------------------*- 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/WatchpointLocation.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+WatchpointLocation::WatchpointLocation (lldb::addr_t addr, lldb::tid_t tid, bool hardware) :
+ StoppointLocation (GetNextID(), addr, tid, hardware),
+ m_enabled(0),
+ m_watch_read(0),
+ m_watch_write(0),
+ m_watch_was_read(0),
+ m_watch_was_written(0),
+ m_ignore_count(0),
+ m_callback(NULL),
+ m_callback_baton(NULL)
+{
+}
+
+WatchpointLocation::~WatchpointLocation()
+{
+}
+
+break_id_t
+WatchpointLocation::GetNextID()
+{
+ static break_id_t g_next_ID = 0;
+ return ++g_next_ID;
+}
+
+bool
+WatchpointLocation::SetCallback (WatchpointHitCallback callback, void *callback_baton)
+{
+ m_callback = callback;
+ m_callback_baton = callback_baton;
+ return true;
+}
+
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue.
+
+bool
+WatchpointLocation::BreakpointWasHit (StoppointCallbackContext *context)
+{
+ m_hit_count++;
+
+ if (m_hit_count > m_ignore_count)
+ {
+ uint32_t access = 0;
+ if (m_watch_was_read)
+ access |= LLDB_WATCH_TYPE_READ;
+ if (m_watch_was_written)
+ access |= LLDB_WATCH_TYPE_WRITE;
+ return m_callback(m_callback_baton, context, GetID(), access);
+ }
+ return false;
+}
+
+void
+WatchpointLocation::Dump(Stream *s) const
+{
+ if (s == NULL)
+ return;
+
+ s->Printf("WatchpointLocation %u: tid = %4.4x addr = 0x%8.8llx size = %zu state = %s type = %s watchpoint (%s%s) hw_index = %i hit_count = %-4u ignore_count = %-4u callback = %8p baton = %8p",
+ GetID(),
+ m_tid,
+ (uint64_t)m_addr,
+ m_byte_size,
+ m_enabled ? "enabled " : "disabled",
+ IsHardware() ? "hardware" : "software",
+ m_watch_read ? "r" : "",
+ m_watch_write ? "w" : "",
+ GetHardwareIndex(),
+ GetHitCount(),
+ GetIgnoreCount(),
+ m_callback,
+ m_callback_baton);
+}
+
+bool
+WatchpointLocation::IsEnabled() const
+{
+ return m_enabled;
+}
+
+void
+WatchpointLocation::SetEnabled(uint32_t enabled)
+{
+ if (!enabled)
+ SetHardwareIndex(LLDB_INVALID_INDEX32);
+ m_enabled = enabled;
+}
+
+void
+WatchpointLocation::SetWatchpointType (uint32_t type)
+{
+ m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
+ m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
+}
+
+bool
+WatchpointLocation::WatchpointRead () const
+{
+ return m_watch_read != 0;
+}
+bool
+WatchpointLocation::WatchpointWrite () const
+{
+ return m_watch_write != 0;
+}
+int32_t
+WatchpointLocation::GetIgnoreCount () const
+{
+ return m_ignore_count;
+}
+
+void
+WatchpointLocation::SetIgnoreCount (int32_t n)
+{
+ m_ignore_count = n;
+}
diff --git a/lldb/source/Commands/CommandObjectAdd.cpp b/lldb/source/Commands/CommandObjectAdd.cpp
new file mode 100644
index 00000000000..cd1d02d22ff
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectAdd.cpp
@@ -0,0 +1,51 @@
+//===-- CommandObjectAdd.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectAdd.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectAdd
+//-------------------------------------------------------------------------
+
+CommandObjectAdd::CommandObjectAdd () :
+ CommandObject ("add",
+ "Allows the user to add a new command/function pair to the debugger's dictionary.",
+ "add <new-command-name> <script-function-name>")
+{
+}
+
+CommandObjectAdd::~CommandObjectAdd()
+{
+}
+
+
+bool
+CommandObjectAdd::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ result.AppendMessage ("This function has not been implemented yet.");
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+}
diff --git a/lldb/source/Commands/CommandObjectAdd.h b/lldb/source/Commands/CommandObjectAdd.h
new file mode 100644
index 00000000000..9aa59b61a7a
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectAdd.h
@@ -0,0 +1,43 @@
+//===-- CommandObjectAdd.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectAdd_h_
+#define liblldb_CommandObjectAdd_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+//-------------------------------------------------------------------------
+// CommandObjectAdd
+//-------------------------------------------------------------------------
+
+class CommandObjectAdd : public CommandObject
+{
+public:
+
+ CommandObjectAdd ();
+
+ virtual
+ ~CommandObjectAdd ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectAdd_h_
diff --git a/lldb/source/Commands/CommandObjectAlias.cpp b/lldb/source/Commands/CommandObjectAlias.cpp
new file mode 100644
index 00000000000..50c2ab92e9f
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectAlias.cpp
@@ -0,0 +1,225 @@
+//===-- CommandObjectAlias.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectAlias.h"
+
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectAlias
+//-------------------------------------------------------------------------
+
+CommandObjectAlias::CommandObjectAlias () :
+ CommandObject ("alias",
+ "Allows users to define their own debugger command abbreviations.",
+ "alias <new_command> <old_command> [<options-for-aliased-command>]")
+{
+ 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 'alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\
+ // command. \n\
+ '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\
+ 'alias bpi breakpoint list' // Creates the abbreviation 'bpi' 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\
+ '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. So 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). So 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 (dbg) alias bfl breakpoint set -f %1 -l %2 \n\
+ <... some time later ...> \n\
+ (dbg) 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 (dbg) alias pltty process launch -s -o %1 -e %1 \n\
+ (dbg) 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 alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\
+ // 3 of whatever file is indicated. \n");
+
+}
+
+CommandObjectAlias::~CommandObjectAlias ()
+{
+}
+
+
+bool
+CommandObjectAlias::Execute (Args& args, CommandContext *context, CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+{
+ const int 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 (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(interpreter->GetCommandSP (actual_command.c_str()));
+ CommandObjectSP subcommand_obj_sp;
+ bool use_subcommand = false;
+ if (command_obj_sp.get())
+ {
+ CommandObject *cmd_obj = command_obj_sp.get();
+ CommandObject *sub_cmd_obj;
+ OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+
+ if (cmd_obj->IsMultiwordObject())
+ {
+ if (argc >= 3)
+ {
+ const std::string sub_command = args.GetArgumentAtIndex(0);
+ assert (sub_command.length() != 0);
+ subcommand_obj_sp =
+ (((CommandObjectMultiword *) 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.
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Error occurred while attempting to look up command '%s %s'.\n",
+ alias_command.c_str(), sub_command.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ // Verify & handle any options/arguments passed to the alias command
+
+ if (args.GetArgumentCount () > 0)
+ {
+ if ((!use_subcommand && (cmd_obj->WantsRawCommandString()))
+ || (use_subcommand && (sub_cmd_obj->WantsRawCommandString())))
+ {
+ result.AppendErrorWithFormat ("'%s' cannot be aliased with any options or arguments.\n",
+ (use_subcommand ? sub_cmd_obj->GetCommandName()
+ : cmd_obj->GetCommandName()));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // options or arguments have been passed to the alias command, and must be verified & processed here.
+ if ((!use_subcommand && (cmd_obj->GetOptions() != NULL))
+ || (use_subcommand && (sub_cmd_obj->GetOptions() != NULL)))
+ {
+ Options *options;
+ if (use_subcommand)
+ options = sub_cmd_obj->GetOptions();
+ else
+ options = cmd_obj->GetOptions();
+ options->ResetOptionValues ();
+ args.Unshift ("dummy_arg");
+ args.ParseAliasOptions (*options, result, option_arg_vector);
+ args.Shift ();
+ if (result.Succeeded())
+ options->VerifyPartialOptions (result);
+ if (!result.Succeeded())
+ return false;
+ }
+ else
+ {
+ for (int i = 0; i < args.GetArgumentCount(); ++i)
+ option_arg_vector->push_back (OptionArgPair ("<argument>",
+ std::string (args.GetArgumentAtIndex (i))));
+ }
+ }
+
+ // Create the alias.
+
+ if (interpreter->AliasExists (alias_command.c_str())
+ || interpreter->UserCommandExists (alias_command.c_str()))
+ {
+ OptionArgVectorSP tmp_option_arg_sp (interpreter->GetAliasOptions (alias_command.c_str()));
+ if (tmp_option_arg_sp.get())
+ {
+ if (option_arg_vector->size() == 0)
+ interpreter->RemoveAliasOptions (alias_command.c_str());
+ }
+ result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", alias_command.c_str());
+ }
+
+ if (use_subcommand)
+ interpreter->AddAlias (alias_command.c_str(), subcommand_obj_sp);
+ else
+ interpreter->AddAlias (alias_command.c_str(), command_obj_sp);
+ if (option_arg_vector->size() > 0)
+ 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 result.Succeeded();
+}
+
diff --git a/lldb/source/Commands/CommandObjectAlias.h b/lldb/source/Commands/CommandObjectAlias.h
new file mode 100644
index 00000000000..859b7cea049
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectAlias.h
@@ -0,0 +1,43 @@
+//===-- CommandObjectAlias.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectAlias_h_
+#define liblldb_CommandObjectAlias_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectAlias
+//-------------------------------------------------------------------------
+
+class CommandObjectAlias : public CommandObject
+{
+public:
+
+ CommandObjectAlias ();
+
+ virtual
+ ~CommandObjectAlias ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectAlias_h_
diff --git a/lldb/source/Commands/CommandObjectAppend.cpp b/lldb/source/Commands/CommandObjectAppend.cpp
new file mode 100644
index 00000000000..613b85b4be9
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectAppend.cpp
@@ -0,0 +1,95 @@
+//===-- CommandObjectAppend.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectAppend.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;
+
+//-----------------------------------------------------------------------------
+// CommandObjectAppend
+//-----------------------------------------------------------------------------
+
+CommandObjectAppend::CommandObjectAppend () :
+ CommandObject ("append",
+ "Allows the user to append a value to a single debugger setting variable, for settings that are of list types. Type 'settings' to see a list of debugger setting variables",
+ "append <var-name> <value-string>")
+{
+}
+
+CommandObjectAppend::~CommandObjectAppend ()
+{
+}
+
+bool
+CommandObjectAppend::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ CommandInterpreter::VariableMap::iterator pos;
+
+ const int argc = command.GetArgumentCount();
+ if (argc < 2)
+ {
+ result.AppendError ("'append' requires at least two arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = command.GetArgumentAtIndex(0);
+ command.Shift();
+
+
+ if (var_name == NULL || var_name[0] == '\0')
+ {
+ result.AppendError ("'set' command requires a valid variable name. No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ StateVariable *var = interpreter->GetStateVariable(var_name);
+ if (var == NULL)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a settable internal variable.\n", var_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ if (var->GetType() == StateVariable::eTypeString)
+ {
+ for (int i = 0; i < command.GetArgumentCount(); ++i)
+ var->AppendStringValue (command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else if (var->GetType() == StateVariable::eTypeStringArray)
+ {
+ var->GetArgs().AppendArguments (command);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Values cannot be appended to variable '%s'. Try 'set' instead.\n", var_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ return result.Succeeded();
+}
+
diff --git a/lldb/source/Commands/CommandObjectAppend.h b/lldb/source/Commands/CommandObjectAppend.h
new file mode 100644
index 00000000000..436283730fb
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectAppend.h
@@ -0,0 +1,43 @@
+//===-- CommandObjectAppend.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectAppend_h_
+#define liblldb_CommandObjectAppend_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+//-----------------------------------------------------------------------------
+// CommandObjectAppend
+//-----------------------------------------------------------------------------
+
+class CommandObjectAppend : public CommandObject
+{
+public:
+ CommandObjectAppend ();
+
+ virtual
+ ~CommandObjectAppend ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectAppend_h_
diff --git a/lldb/source/Commands/CommandObjectApropos.cpp b/lldb/source/Commands/CommandObjectApropos.cpp
new file mode 100644
index 00000000000..0fcc093901f
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectApropos.cpp
@@ -0,0 +1,96 @@
+//===-- 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 "CommandObjectApropos.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Options.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectApropos
+//-------------------------------------------------------------------------
+
+CommandObjectApropos::CommandObjectApropos () :
+ CommandObject ("apropos",
+ "Finds a list of debugger commands related to a particular word/subject.",
+ "apropos <search-word>")
+{
+}
+
+CommandObjectApropos::~CommandObjectApropos()
+{
+}
+
+
+bool
+CommandObjectApropos::Execute (Args &command, CommandContext *context, CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+{
+ const int argc = command.GetArgumentCount ();
+
+ if (argc == 1)
+ {
+ const char *search_word = command.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;
+ interpreter->FindCommandsForApropos (search_word, commands_found, commands_help);
+ if (commands_found.GetSize() == 0)
+ {
+ result.AppendMessageWithFormat ("No commands found pertaining to '%s'.", search_word);
+ result.AppendMessage ("Try 'help' to see a complete list of debugger commands.");
+ }
+ else
+ {
+ result.AppendMessageWithFormat ("The following commands may relate to '%s':\n", search_word);
+ size_t max_len = 0;
+
+ for (int i = 0; i < commands_found.GetSize(); ++i)
+ {
+ int len = strlen (commands_found.GetStringAtIndex (i));
+ if (len > max_len)
+ max_len = len;
+ }
+
+ for (int i = 0; i < commands_found.GetSize(); ++i)
+ interpreter->OutputFormattedHelpText (result.GetOutputStream(), commands_found.GetStringAtIndex(i),
+ "--", commands_help.GetStringAtIndex(i), max_len);
+
+ }
+ 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/lldb/source/Commands/CommandObjectApropos.h b/lldb/source/Commands/CommandObjectApropos.h
new file mode 100644
index 00000000000..a079a3fc4ac
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectApropos.h
@@ -0,0 +1,45 @@
+//===-- 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 CommandObject
+{
+public:
+
+ CommandObjectApropos ();
+
+ virtual
+ ~CommandObjectApropos ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectApropos_h_
diff --git a/lldb/source/Commands/CommandObjectArgs.cpp b/lldb/source/Commands/CommandObjectArgs.cpp
new file mode 100644
index 00000000000..7f1fd3dda94
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectArgs.cpp
@@ -0,0 +1,279 @@
+//===-- 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 "CommandObjectArgs.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.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/CommandContext.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 () :
+Options()
+{
+ // Keep only one place to reset the values to their defaults
+ ResetOptionValues();
+}
+
+
+CommandObjectArgs::CommandOptions::~CommandOptions ()
+{
+}
+
+Error
+CommandObjectArgs::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
+{
+ Error error;
+
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ default:
+ error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectArgs::CommandOptions::ResetOptionValues ()
+{
+ Options::ResetOptionValues();
+}
+
+const lldb::OptionDefinition*
+CommandObjectArgs::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+CommandObjectArgs::CommandObjectArgs () :
+ CommandObject ("args",
+ "When stopped at the start of a function, reads function arguments of type (u?)int(8|16|32|64)_t, (void|char)*",
+ "args")
+{
+}
+
+CommandObjectArgs::~CommandObjectArgs ()
+{
+}
+
+Options *
+CommandObjectArgs::GetOptions ()
+{
+ return &m_options;
+}
+
+bool
+CommandObjectArgs::Execute(Args &command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+{
+ ConstString target_triple;
+
+ Process *process = context->GetExecutionContext().process;
+ if (!process)
+ {
+ result.AppendError ("Args found no process.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const ABI *abi = process->GetABI ();
+ if (!abi)
+ {
+ result.AppendError ("The current process has no ABI.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ int num_args = command.GetArgumentCount ();
+ int arg_index;
+
+ if (!num_args)
+ {
+ result.AppendError ("args requires at least one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Thread *thread = context->GetExecutionContext ().thread;
+
+ if (!thread)
+ {
+ result.AppendError ("args found no thread.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ lldb::StackFrameSP thread_cur_frame = thread->GetCurrentFrame ();
+ if (!thread_cur_frame)
+ {
+ result.AppendError ("The current thread has no current frame.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Module *thread_module = thread_cur_frame->GetPC ().GetModule ();
+ if (!thread_module)
+ {
+ result.AppendError ("The PC has no associated module.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ TypeList *thread_type_list = thread_module->GetTypeList ();
+ if (!thread_type_list)
+ {
+ result.AppendError ("The module has no type list.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ClangASTContext &ast_context = thread_type_list->GetClangASTContext();
+
+ ValueList value_list;
+
+ for (arg_index = 0; arg_index < num_args; ++arg_index)
+ {
+ const char *arg_type_cstr = command.GetArgumentAtIndex(arg_index);
+ Value value;
+ value.SetValueType(Value::eValueTypeScalar);
+ void *type;
+
+ char *int_pos;
+ if ((int_pos = strstr (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;
+ }
+
+ type = ast_context.GetBuiltinTypeForEncodingAndBitSize(encoding, width);
+
+ if (!type)
+ {
+ 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*"))
+ type = ast_context.CreatePointerType (ast_context.GetVoidBuiltInType ());
+ else if (!strcmp (arg_type_cstr, "char*"))
+ 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.SetContext (Value::eContextTypeOpaqueClangQualType, 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 ("%d (%s): ", arg_index, command.GetArgumentAtIndex (arg_index));
+ value_list.GetValueAtIndex (arg_index)->Dump (&result.GetOutputStream ());
+ result.GetOutputStream ().Printf("\n");
+ }
+
+ return result.Succeeded();
+}
+
+lldb::OptionDefinition
+CommandObjectArgs::CommandOptions::g_option_table[] =
+{
+ { 0, false, "debug", 'g', no_argument, NULL, 0, NULL, "Enable verbose debug logging of the expression parsing and evaluation."},
+ { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
+};
+
diff --git a/lldb/source/Commands/CommandObjectArgs.h b/lldb/source/Commands/CommandObjectArgs.h
new file mode 100644
index 00000000000..d326d423247
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectArgs.h
@@ -0,0 +1,76 @@
+//===-- 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/Core/Options.h"
+#include "lldb/Core/Language.h"
+
+namespace lldb_private {
+
+ class CommandObjectArgs : public CommandObject
+ {
+ public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions ();
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg);
+
+ void
+ ResetOptionValues ();
+
+ const lldb::OptionDefinition*
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+ };
+
+ CommandObjectArgs ();
+
+ virtual
+ ~CommandObjectArgs ();
+
+ virtual
+ Options *
+ GetOptions ();
+
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual bool
+ WantsRawCommandString() { return false; }
+
+ protected:
+
+ CommandOptions m_options;
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectArgs_h_
diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp
new file mode 100644
index 00000000000..d24ba8f553b
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -0,0 +1,953 @@
+//===-- 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 "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/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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static void
+AddBreakpointDescription (CommandContext *context, StreamString *s, Breakpoint *bp, lldb::DescriptionLevel level)
+{
+ s->IndentMore();
+ bp->GetDescription (s, level, true);
+ s->IndentLess();
+ s->EOL();
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointSet::CommandOptions
+//-------------------------------------------------------------------------
+
+CommandObjectBreakpointSet::CommandOptions::CommandOptions() :
+ Options (),
+ m_filename (),
+ m_line_num (0),
+ m_column (0),
+ m_ignore_inlines (false),
+ m_func_name (),
+ m_func_regexp (),
+ m_modules (),
+ m_load_addr()
+{
+ BuildValidOptionSets();
+}
+
+CommandObjectBreakpointSet::CommandOptions::~CommandOptions ()
+{
+}
+
+lldb::OptionDefinition
+CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
+{
+ { 0, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, "<filename>",
+ "Set the breakpoint by source location in this particular file."},
+
+ { 0, true, "line", 'l', required_argument, NULL, 0, "<linenum>",
+ "Set the breakpoint by source location at this particular line."},
+
+ { 0, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, "<shlib-name>",
+ "Set the breakpoint only in this shared library (can use this option multiple times for multiple shlibs)."},
+
+ // 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."},
+
+ { 0, false, "ignore_inlines", 'i', no_argument, NULL, 0, NULL,
+ "Ignore inlined subroutines when setting the breakppoint." },
+
+ { 1, true, "address", 'a', required_argument, NULL, 0, "<address>",
+ "Set the breakpoint by address, at the specified address."},
+
+ { 1, false, "ignore_inlines", 'i', no_argument, NULL, 0, NULL,
+ "Ignore inlined subroutines when setting the breakppoint." },
+
+ { 2, true, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, "<function-name>",
+ "Set the breakpoint by function name." },
+
+ { 2, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, "<shlib-name>",
+ "Set the breakpoint only in this shared library (can use this option multiple times for multiple shlibs)."},
+
+ { 2, false, "ignore_inlines", 'i', no_argument, NULL, 0, NULL,
+ "Ignore inlined subroutines when setting the breakpoint." },
+
+ { 3, true, "func_regex", 'r', required_argument, NULL, 0, "<regular-expression>",
+ "Set the breakpoint by function name, evaluating a regular-expression to find the function name(s)." },
+
+ { 3, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, "<shlib-name>",
+ "Set the breakpoint only in this shared library (can use this option multiple times for multiple shlibs)."},
+
+ { 3, false, "ignore_inlines", 'i', no_argument, NULL, 0, NULL,
+ "Ignore inlined subroutines when setting the breakpoint." },
+
+ { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+const lldb::OptionDefinition*
+CommandObjectBreakpointSet::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+Error
+CommandObjectBreakpointSet::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
+{
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 0);
+ if (m_load_addr == LLDB_INVALID_ADDRESS)
+ m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 16);
+
+ if (m_load_addr == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat ("Invalid address string '%s'.\n", optarg);
+ break;
+
+ case 'c':
+ m_column = Args::StringToUInt32 (option_arg, 0);
+ break;
+ case 'f':
+ m_filename = option_arg;
+ break;
+ case 'i':
+ m_ignore_inlines = true;
+ break;
+ case 'l':
+ m_line_num = Args::StringToUInt32 (option_arg, 0);
+ break;
+ case 'n':
+ m_func_name = option_arg;
+ break;
+ case 'r':
+ m_func_regexp = option_arg;
+ break;
+ case 's':
+ {
+ m_modules.push_back (std::string (option_arg));
+ break;
+ }
+ default:
+ error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectBreakpointSet::CommandOptions::ResetOptionValues ()
+{
+ Options::ResetOptionValues();
+
+ m_filename.clear();
+ m_line_num = 0;
+ m_column = 0;
+ m_ignore_inlines = false;
+ m_func_name.clear();
+ m_func_regexp.clear();
+ m_load_addr = LLDB_INVALID_ADDRESS;
+ m_modules.clear();
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointSet
+//-------------------------------------------------------------------------
+
+CommandObjectBreakpointSet::CommandObjectBreakpointSet () :
+ CommandObject ("breakpoint set", "Sets a breakpoint or set of breakpoints in the executable.",
+ "breakpoint set <cmd-options>")
+{
+}
+
+CommandObjectBreakpointSet::~CommandObjectBreakpointSet ()
+{
+}
+
+Options *
+CommandObjectBreakpointSet::GetOptions ()
+{
+ return &m_options;
+}
+
+bool
+CommandObjectBreakpointSet::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target, set executable file using 'file' 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)
+
+ 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_name.empty())
+ break_type = eSetTypeFunctionName;
+ else if (!m_options.m_func_regexp.empty())
+ break_type = eSetTypeFunctionRegexp;
+
+ ModuleSP module_sp = target->GetExecutableModule();
+ Breakpoint *bp = NULL;
+ FileSpec module;
+ bool use_module = false;
+ int num_modules = m_options.m_modules.size();
+
+ if ((num_modules > 0) && (break_type != eSetTypeAddress))
+ use_module = true;
+
+ switch (break_type)
+ {
+ case eSetTypeFileAndLine: // Breakpoint by source position
+ {
+ FileSpec file;
+ if (m_options.m_filename.empty())
+ {
+ StackFrame *cur_frame = context->GetExecutionContext().frame;
+ if (cur_frame == NULL)
+ {
+ result.AppendError ("Attempting to set breakpoint by line number alone with no selected frame.");
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ else if (!cur_frame->HasDebugInformation())
+ {
+ result.AppendError ("Attempting to set breakpoint by line number alone but selected frame has no debug info.");
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ else
+ {
+ const SymbolContext &context = cur_frame->GetSymbolContext(true);
+ if (context.line_entry.file)
+ {
+ file = context.line_entry.file;
+ }
+ else if (context.comp_unit != NULL)
+ { file = context.comp_unit;
+ }
+ else
+ {
+ result.AppendError ("Attempting to set breakpoint by line number alone but can't find the file for the selected frame.");
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ }
+ else
+ {
+ file.SetFile(m_options.m_filename.c_str());
+ }
+
+ if (use_module)
+ {
+ for (int i = 0; i < num_modules; ++i)
+ {
+ module.SetFile(m_options.m_modules[i].c_str());
+ bp = target->CreateBreakpoint (&module,
+ file,
+ m_options.m_line_num,
+ m_options.m_ignore_inlines).get();
+ if (bp)
+ {
+ StreamString &output_stream = result.GetOutputStream();
+ output_stream.Printf ("Breakpoint created: ");
+ bp->GetDescription(&output_stream, lldb::eDescriptionLevelBrief);
+ output_stream.EOL();
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Breakpoint creation failed: No breakpoint created in module '%s'.\n",
+ m_options.m_modules[i].c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ bp = target->CreateBreakpoint (NULL,
+ file,
+ m_options.m_line_num,
+ m_options.m_ignore_inlines).get();
+ }
+ break;
+ case eSetTypeAddress: // Breakpoint by address
+ bp = target->CreateBreakpoint (m_options.m_load_addr, false).get();
+ break;
+ case eSetTypeFunctionName: // Breakpoint by function name
+ if (use_module)
+ {
+ for (int i = 0; i < num_modules; ++i)
+ {
+ module.SetFile(m_options.m_modules[i].c_str());
+ bp = target->CreateBreakpoint (&module, m_options.m_func_name.c_str()).get();
+ if (bp)
+ {
+ StreamString &output_stream = result.GetOutputStream();
+ output_stream.Printf ("Breakpoint created: ");
+ bp->GetDescription(&output_stream, lldb::eDescriptionLevelBrief);
+ output_stream.EOL();
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Breakpoint creation failed: No breakpoint created in module '%s'.\n",
+ m_options.m_modules[i].c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ bp = target->CreateBreakpoint (NULL, m_options.m_func_name.c_str()).get();
+ break;
+ case eSetTypeFunctionRegexp: // Breakpoint by regular expression function name
+ {
+ RegularExpression regexp(m_options.m_func_regexp.c_str());
+ if (use_module)
+ {
+ for (int i = 0; i < num_modules; ++i)
+ {
+ module.SetFile(m_options.m_modules[i].c_str());
+ bp = target->CreateBreakpoint (&module, regexp).get();
+ if (bp)
+ {
+ StreamString &output_stream = result.GetOutputStream();
+ output_stream.Printf ("Breakpoint created: ");
+ bp->GetDescription(&output_stream, lldb::eDescriptionLevelBrief);
+ output_stream.EOL();
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Breakpoint creation failed: No breakpoint created in module '%s'.\n",
+ m_options.m_modules[i].c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ bp = target->CreateBreakpoint (NULL, regexp).get();
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (bp && !use_module)
+ {
+ StreamString &output_stream = result.GetOutputStream();
+ output_stream.Printf ("Breakpoint created: ");
+ bp->GetDescription(&output_stream, lldb::eDescriptionLevelBrief);
+ output_stream.EOL();
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else if (!bp)
+ {
+ result.AppendError ("Breakpoint creation failed: No breakpoint created.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+}
+
+
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordBreakpoint
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInterpreter *interpreter) :
+ CommandObjectMultiword ("breakpoint",
+ "A set of commands for operating on breakpoints.",
+ "breakpoint <command> [<command-options>]")
+{
+ bool status;
+
+ CommandObjectSP list_command_object (new CommandObjectBreakpointList ());
+ CommandObjectSP delete_command_object (new CommandObjectBreakpointDelete ());
+ CommandObjectSP enable_command_object (new CommandObjectBreakpointEnable ());
+ CommandObjectSP disable_command_object (new CommandObjectBreakpointDisable ());
+ CommandObjectSP set_command_object (new CommandObjectBreakpointSet ());
+ CommandObjectSP command_command_object (new CommandObjectBreakpointCommand (interpreter));
+
+ enable_command_object->SetCommandName("breakpoint enable");
+ disable_command_object->SetCommandName("breakpoint disable");
+ set_command_object->SetCommandName("breakpoint set");
+ command_command_object->SetCommandName ("breakpoint command");
+ list_command_object->SetCommandName ("breakpoint list");
+
+ status = LoadSubCommand (list_command_object, "list", interpreter);
+ status = LoadSubCommand (enable_command_object, "enable", interpreter);
+ status = LoadSubCommand (disable_command_object, "disable", interpreter);
+ status = LoadSubCommand (delete_command_object, "delete", interpreter);
+ status = LoadSubCommand (set_command_object, "set", interpreter);
+ status = LoadSubCommand (command_command_object, "command", interpreter);
+}
+
+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.
+
+ Args temp_args;
+
+ // 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 ((const char **) temp_args.GetArgumentVector(), 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.
+
+ for (int i = 0; i < valid_ids->Size(); ++i)
+ {
+ BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex (i);
+ Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ if (breakpoint != NULL)
+ {
+ int 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->Size() + 1;
+ result.AppendErrorWithFormat ("'%s' is not a currently valid breakpoint/location id.\n",
+ id_str.GetData());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ i = valid_ids->Size() + 1;
+ result.AppendErrorWithFormat ("'%d' is not a currently valid breakpoint id.\n", cur_bp_id.GetBreakpointID());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointList::Options
+//-------------------------------------------------------------------------
+
+CommandObjectBreakpointList::CommandOptions::CommandOptions() :
+ Options (),
+ m_level (lldb::eDescriptionLevelFull) // Breakpoint List defaults to brief descriptions
+{
+ BuildValidOptionSets();
+}
+
+CommandObjectBreakpointList::CommandOptions::~CommandOptions ()
+{
+}
+
+lldb::OptionDefinition
+CommandObjectBreakpointList::CommandOptions::g_option_table[] =
+{
+ { 0, false, "brief", 'b', no_argument, NULL, 0, NULL,
+ "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.
+ { 0, false, "internal", 'i', no_argument, NULL, 0, NULL,
+ "Show debugger internal breakpoints" },
+
+ { 1, false, "full", 'f', no_argument, NULL, 0, NULL,
+ "Give a full description of the breakpoint and its locations."},
+ // DITTO FIXME
+ { 1, false, "internal", 'i', no_argument, NULL, 0, NULL,
+ "Show debugger internal breakpoints" },
+
+ { 2, false, "verbose", 'v', no_argument, NULL, 0, NULL,
+ "Explain everything we know about the breakpoint (for debugging debugger bugs)." },
+ // DITTO FIXME
+ { 2, false, "internal", 'i', no_argument, NULL, 0, NULL,
+ "Show debugger internal breakpoints" },
+
+ { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+const lldb::OptionDefinition*
+CommandObjectBreakpointList::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+Error
+CommandObjectBreakpointList::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
+{
+ Error error;
+ char short_option = (char) 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'.\n", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectBreakpointList::CommandOptions::ResetOptionValues ()
+{
+ Options::ResetOptionValues();
+
+ m_level = lldb::eDescriptionLevelFull;
+ m_internal = false;
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointList
+//-------------------------------------------------------------------------
+
+CommandObjectBreakpointList::CommandObjectBreakpointList () :
+ CommandObject ("breakpoint list",
+ "List some or all breakpoints at configurable levels of detail.",
+ "breakpoint list [<breakpoint-id>]")
+{
+}
+
+CommandObjectBreakpointList::~CommandObjectBreakpointList ()
+{
+}
+
+Options *
+CommandObjectBreakpointList::GetOptions ()
+{
+ return &m_options;
+}
+
+bool
+CommandObjectBreakpointList::Execute
+(
+ Args& args,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target, set executable file using 'file' command.");
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ const BreakpointList &breakpoints = target->GetBreakpointList(m_options.m_internal);
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ if (num_breakpoints == 0)
+ {
+ result.AppendMessage ("No breakpoints currently set.");
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ StreamString &output_stream = result.GetOutputStream();
+
+ if (args.GetArgumentCount() == 0)
+ {
+ // No breakpoint selected; show info about all currently set breakpoints.
+ result.AppendMessage ("Current breakpoints:");
+ for (int i = 0; i < num_breakpoints; ++i)
+ {
+ Breakpoint *breakpoint = breakpoints.GetBreakpointByIndex (i).get();
+ AddBreakpointDescription (context, &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 (args, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ for (int i = 0; i < valid_bp_ids.Size(); ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+ Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ AddBreakpointDescription (context, &output_stream, breakpoint, m_options.m_level);
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("Invalid breakpoint id.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+
+ return result.Succeeded();
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointEnable
+//-------------------------------------------------------------------------
+
+CommandObjectBreakpointEnable::CommandObjectBreakpointEnable () :
+ CommandObject ("enable",
+ "Enables the specified disabled breakpoint(s). If no breakpoints are specified, enables all of them.",
+ "breakpoint enable [<breakpoint-id> | <breakpoint-id-list>]")
+{
+ // This command object can either be called via 'enable' or 'breakpoint enable'. Because it has two different
+ // potential invocation methods, we need to be a little tricky about generating the syntax string.
+ //StreamString tmp_string;
+ //tmp_string.Printf ("%s <breakpoint-id>", GetCommandName());
+ //m_cmd_syntax.assign (tmp_string.GetData(), tmp_string.GetSize());
+}
+
+
+CommandObjectBreakpointEnable::~CommandObjectBreakpointEnable ()
+{
+}
+
+
+bool
+CommandObjectBreakpointEnable::Execute (Args& args, CommandContext *context,
+ CommandInterpreter *interpreter, CommandReturnObject &result)
+{
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target, set executable file using 'file' command.");
+ 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 be enabled.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (args.GetArgumentCount() == 0)
+ {
+ // No breakpoint selected; enable all currently set breakpoints.
+ target->EnableAllBreakpoints ();
+ result.AppendMessageWithFormat ("All breakpoints enabled. (%d breakpoints)\n", num_breakpoints);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular breakpoint selected; enable that breakpoint.
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (args, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ int enable_count = 0;
+ int loc_count = 0;
+ for (int i = 0; i < valid_bp_ids.Size(); ++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);
+ breakpoint->SetEnabled (true);
+ ++loc_count;
+ }
+ }
+ else
+ {
+ target->EnableBreakpointByID (cur_bp_id.GetBreakpointID());
+ ++enable_count;
+
+ int num_locations = breakpoint->GetNumLocations ();
+ for (int j = 0; j < num_locations; ++j)
+ {
+ BreakpointLocation *cur_loc = breakpoint->GetLocationAtIndex(j).get();
+ if (cur_loc)
+ cur_loc->SetEnabled (true);
+ }
+ }
+ }
+ }
+ result.AppendMessageWithFormat ("%d breakpoints enabled.\n", enable_count + loc_count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+
+ return result.Succeeded();
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointDisable
+//-------------------------------------------------------------------------
+
+CommandObjectBreakpointDisable::CommandObjectBreakpointDisable () :
+ CommandObject ("disable",
+ "Disables the specified breakpoint(s) without removing it/them. If no breakpoints are specified, disables them all.",
+ "disable [<breakpoint-id> | <breakpoint-id-list>]")
+{
+ // This command object can either be called via 'enable' or 'breakpoint enable'. Because it has two different
+ // potential invocation methods, we need to be a little tricky about generating the syntax string.
+ //StreamString tmp_string;
+ //tmp_string.Printf ("%s <breakpoint-id>", GetCommandName());
+ //m_cmd_syntax.assign(tmp_string.GetData(), tmp_string.GetSize());
+}
+
+CommandObjectBreakpointDisable::~CommandObjectBreakpointDisable ()
+{
+}
+
+bool
+CommandObjectBreakpointDisable::Execute (Args& args, CommandContext *context,
+ CommandInterpreter *interpreter, CommandReturnObject &result)
+{
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target, set executable file using 'file' command.");
+ 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 be disabled.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (args.GetArgumentCount() == 0)
+ {
+ // No breakpoint selected; disable all currently set breakpoints.
+ target->DisableAllBreakpoints ();
+ result.AppendMessageWithFormat ("All breakpoints disabled. (%d breakpoints)\n", num_breakpoints);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular breakpoint selected; disable that breakpoint.
+ BreakpointIDList valid_bp_ids;
+
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (args, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ int disable_count = 0;
+ int loc_count = 0;
+ for (int i = 0; i < valid_bp_ids.Size(); ++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
+ {
+ target->DisableBreakpointByID (cur_bp_id.GetBreakpointID());
+ ++disable_count;
+
+ int num_locations = breakpoint->GetNumLocations();
+ for (int j = 0; j < num_locations; ++j)
+ {
+ BreakpointLocation *cur_loc = breakpoint->GetLocationAtIndex(j).get();
+ if (cur_loc)
+ cur_loc->SetEnabled (false);
+ }
+ }
+ }
+ }
+ result.AppendMessageWithFormat ("%d breakpoints disabled.\n", disable_count + loc_count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+
+ return result.Succeeded();
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointDelete
+//-------------------------------------------------------------------------
+
+CommandObjectBreakpointDelete::CommandObjectBreakpointDelete() :
+ CommandObject ("breakpoint delete",
+ "Delete the specified breakpoint(s). If no breakpoints are specified, deletes them all.",
+ "breakpoint delete [<breakpoint-id> | <breakpoint-id-list>]")
+{
+}
+
+
+CommandObjectBreakpointDelete::~CommandObjectBreakpointDelete ()
+{
+}
+
+bool
+CommandObjectBreakpointDelete::Execute (Args& args, CommandContext *context,
+ CommandInterpreter *interpreter, CommandReturnObject &result)
+{
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target, set executable file using 'file' command.");
+ 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 be deleted.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (args.GetArgumentCount() == 0)
+ {
+ // No breakpoint selected; disable all currently set breakpoints.
+ if (args.GetArgumentCount() != 0)
+ {
+ result.AppendErrorWithFormat ("Specify breakpoints to delete with the -i option.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ target->RemoveAllBreakpoints ();
+ result.AppendMessageWithFormat ("All breakpoints removed. (%d breakpoints)\n", num_breakpoints);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular breakpoint selected; disable that breakpoint.
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (args, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ int delete_count = 0;
+ int disable_count = 0;
+ for (int i = 0; i < valid_bp_ids.Size(); ++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();
+}
diff --git a/lldb/source/Commands/CommandObjectBreakpoint.h b/lldb/source/Commands/CommandObjectBreakpoint.h
new file mode 100644
index 00000000000..49007438b28
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectBreakpoint.h
@@ -0,0 +1,235 @@
+//===-- 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/Core/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);
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordBreakpointSet
+//-------------------------------------------------------------------------
+
+
+class CommandObjectBreakpointSet : public CommandObject
+{
+public:
+
+ typedef enum BreakpointSetType
+ {
+ eSetTypeInvalid,
+ eSetTypeFileAndLine,
+ eSetTypeAddress,
+ eSetTypeFunctionName,
+ eSetTypeFunctionRegexp,
+ } BreakpointSetType;
+
+ CommandObjectBreakpointSet ();
+
+ virtual
+ ~CommandObjectBreakpointSet ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual Options *
+ GetOptions ();
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions ();
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg);
+
+ void
+ ResetOptionValues ();
+
+ const lldb::OptionDefinition*
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string m_filename;
+ unsigned int m_line_num;
+ unsigned int m_column;
+ bool m_ignore_inlines;
+ std::string m_func_name;
+ std::string m_func_regexp;
+ lldb::addr_t m_load_addr;
+ STLStringArray m_modules;
+
+ };
+
+private:
+ CommandOptions m_options;
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointEnable
+//-------------------------------------------------------------------------
+
+class CommandObjectBreakpointEnable : public CommandObject
+{
+public:
+ CommandObjectBreakpointEnable ();
+
+ virtual
+ ~CommandObjectBreakpointEnable ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+private:
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointDisable
+//-------------------------------------------------------------------------
+
+class CommandObjectBreakpointDisable : public CommandObject
+{
+public:
+ CommandObjectBreakpointDisable ();
+
+ virtual
+ ~CommandObjectBreakpointDisable ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+private:
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointList
+//-------------------------------------------------------------------------
+
+class CommandObjectBreakpointList : public CommandObject
+{
+public:
+ CommandObjectBreakpointList ();
+
+ virtual
+ ~CommandObjectBreakpointList ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual Options *
+ GetOptions ();
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions ();
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg);
+
+ void
+ ResetOptionValues ();
+
+ const lldb::OptionDefinition *
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ lldb::DescriptionLevel m_level;
+
+ bool m_internal;
+ };
+
+private:
+ CommandOptions m_options;
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectBreakpointDelete : public CommandObject
+{
+public:
+ CommandObjectBreakpointDelete ();
+
+ virtual
+ ~CommandObjectBreakpointDelete ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+private:
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectBreakpoint_h_
diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
new file mode 100644
index 00000000000..8a5a443ea8e
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -0,0 +1,695 @@
+//===-- CommandObjectBreakpointCommand.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 "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::CommandOptions
+//-------------------------------------------------------------------------
+
+CommandObjectBreakpointCommandAdd::CommandOptions::CommandOptions () :
+ Options ()
+{
+ BuildValidOptionSets();
+}
+
+CommandObjectBreakpointCommandAdd::CommandOptions::~CommandOptions ()
+{
+}
+
+lldb::OptionDefinition
+CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] =
+{
+ { 0, true, "script", 's', no_argument, NULL, 0, NULL,
+ "Write the breakpoint command script in the default scripting language."},
+
+ { 1, true, "python", 'p', no_argument, NULL, 0, NULL,
+ "Write the breakpoint command script in the Python scripting language."},
+
+ { 2, true, "commands", 'c', no_argument, NULL, 0, NULL,
+ "Write the breakpoint command script using the command line commands."},
+
+ { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+const lldb::OptionDefinition*
+CommandObjectBreakpointCommandAdd::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+
+Error
+CommandObjectBreakpointCommandAdd::CommandOptions::SetOptionValue
+(
+ int option_idx,
+ const char *option_arg
+)
+{
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 's':
+ m_use_commands = false;
+ m_use_script_language = true;
+ m_script_language = eScriptLanguageDefault;
+ break;
+ case 'p':
+ m_use_commands = false;
+ m_use_script_language = true;
+ m_script_language = eScriptLanguagePython;
+ break;
+ case 'c':
+ m_use_commands = true;
+ m_use_script_language = false;
+ m_script_language = eScriptLanguageNone;
+ break;
+ default:
+ break;
+ }
+ return error;
+}
+
+void
+CommandObjectBreakpointCommandAdd::CommandOptions::ResetOptionValues ()
+{
+ Options::ResetOptionValues();
+
+ m_use_commands = false;
+ m_use_script_language = false;
+ m_script_language = eScriptLanguageNone;
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommandAdd
+//-------------------------------------------------------------------------
+
+
+CommandObjectBreakpointCommandAdd::CommandObjectBreakpointCommandAdd () :
+ CommandObject ("add",
+ "Adds a set of commands to a breakpoint to be executed whenever a breakpoint is hit.",
+ "breakpoint command add <cmd-options> <breakpoint-id>")
+{
+ SetHelpLong (
+"\nGeneral information about entering breakpoint 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 breakpoint 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 breakpoint 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 breakpoint \n\
+and executed when the breakpoint is hit. \n\
+ \n\
+Syntax checking is not necessarily done when breakpoint commands are \n\
+entered. An improperly written breakpoint command will attempt to get \n\
+executed when the breakpoint gets hit, and usually silently fail. If \n\
+your breakpoint command does not appear to be getting executed, go \n\
+back and check your syntax. \n\
+ \n\
+ \n\
+Special information about PYTHON breakpoint 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 breakpoint gets hit. If you enter function \n\
+definitions, they will be passed to the Python interpreter as soon as \n\
+you finish entering the breakpoint command, and they can be called \n\
+later (don't forget to add calls to them, if you want them called when \n\
+the breakpoint 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 breakpoint. Important \n\
+Note: Because loose Python code gets collected into functions, if you \n\
+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\
+breakpoint commands. \n\
+ \n\
+Example Python one-line breakpoint command: \n\
+ \n\
+(lldb) breakpoint command add -p 1 \n\
+Enter your Python command(s). Type 'DONE' to end. \n\
+> print \"Hit this breakpoint!\" \n\
+> DONE \n\
+ \n\
+Example multiple line Python breakpoint command, using function definition: \n\
+ \n\
+(lldb) breakpoint command add -p 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 -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\
+Special information debugger command breakpoint 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" );
+}
+
+CommandObjectBreakpointCommandAdd::~CommandObjectBreakpointCommandAdd ()
+{
+}
+
+bool
+CommandObjectBreakpointCommandAdd::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ Target *target = context->GetTarget();
+
+ 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 (command.GetArgumentCount() == 0)
+ {
+ result.AppendError ("No breakpoint specified to which to add the commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ for (int i = 0; i < valid_bp_ids.Size(); ++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)
+ {
+ if (m_options.m_use_script_language)
+ {
+ interpreter->GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_loc_sp->GetLocationOptions(),
+ result);
+ }
+ else
+ {
+ CollectDataForBreakpointCommandCallback (bp_loc_sp->GetLocationOptions(), result);
+ }
+ }
+ }
+ else
+ {
+ if (m_options.m_use_script_language)
+ {
+ interpreter->GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp->GetOptions(),
+ result);
+ }
+ else
+ {
+ CollectDataForBreakpointCommandCallback (bp->GetOptions(), result);
+ }
+ }
+ }
+ }
+ }
+
+ return result.Succeeded();
+}
+
+Options *
+CommandObjectBreakpointCommandAdd::GetOptions ()
+{
+ return &m_options;
+}
+
+const char *g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.";
+
+void
+CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback
+(
+ BreakpointOptions *bp_options,
+ CommandReturnObject &result
+)
+{
+ InputReaderSP reader_sp (new InputReader());
+ std::auto_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 (CommandObjectBreakpointCommand::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())
+ {
+ Debugger::GetSharedInstance().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+}
+
+size_t
+CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback
+(
+ void *baton,
+ InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle();
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ if (out_fh)
+ {
+ ::fprintf (out_fh, "%s\n", g_reader_instructions);
+ if (reader->GetPrompt())
+ ::fprintf (out_fh, "%s", reader->GetPrompt());
+ }
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderReactivate:
+ if (out_fh && reader->GetPrompt())
+ ::fprintf (out_fh, "%s", reader->GetPrompt());
+ 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 (out_fh && !reader->IsDone() && reader->GetPrompt())
+ ::fprintf (out_fh, "%s", reader->GetPrompt());
+ break;
+
+ case eInputReaderDone:
+ break;
+ }
+
+ return bytes_len;
+}
+
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommandRemove
+//-------------------------------------------------------------------------
+
+CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove () :
+ CommandObject ("remove",
+ "Remove the set of commands from a breakpoint.",
+ "breakpoint command remove <breakpoint-id>")
+{
+}
+
+CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove ()
+{
+}
+
+bool
+CommandObjectBreakpointCommandRemove::Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+{
+ Target *target = context->GetTarget();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no breakpoints from which to remove 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 removed");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ result.AppendError ("No breakpoint specified from which to remove the commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ for (int i = 0; i < valid_bp_ids.Size(); ++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
+//-------------------------------------------------------------------------
+
+CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList () :
+ CommandObject ("List",
+ "List the script or set of commands to be executed when the breakpoint is hit.",
+ "breakpoint command list <breakpoint-id>")
+{
+}
+
+CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList ()
+{
+}
+
+bool
+CommandObjectBreakpointCommandList::Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+{
+ Target *target = context->GetTarget();
+
+ 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())
+ {
+ for (int i = 0; i < valid_bp_ids.Size(); ++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)
+ {
+ 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->GetOptionsNoCopy();
+ 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());
+ 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 ("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>")
+{
+ bool status;
+ CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd ());
+ CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove ());
+ CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList ());
+
+ add_command_object->SetCommandName ("breakpoint command add");
+ remove_command_object->SetCommandName ("breakpoint command remove");
+ list_command_object->SetCommandName ("breakpoint command list");
+
+ status = LoadSubCommand (add_command_object, "add", interpreter);
+ status = LoadSubCommand (remove_command_object, "remove", interpreter);
+ status = LoadSubCommand (list_command_object, "list", interpreter);
+}
+
+
+CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
+{
+}
+
+bool
+CommandObjectBreakpointCommand::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)
+ {
+ uint32_t num_commands = commands.GetSize();
+ CommandInterpreter &interpreter = Debugger::GetSharedInstance().GetCommandInterpreter();
+ CommandReturnObject result;
+ ExecutionContext exe_ctx = context->context;
+
+ FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle();
+ FILE *err_fh = Debugger::GetSharedInstance().GetErrorFileHandle();
+
+
+ uint32_t i;
+ for (i = 0; i < num_commands; ++i)
+ {
+
+ // First time through we use the context from the stoppoint, after that we use whatever
+ // has been set by the previous command.
+
+ if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &exe_ctx))
+ break;
+
+ // FIXME: This isn't really the right way to do this. We should be able to peek at the public
+ // to see if there is any new events, but that is racey, since the internal process thread has to run and
+ // deliver the event to the public queue before a run will show up. So for now we check
+ // the internal thread state.
+
+ lldb::StateType internal_state = exe_ctx.process->GetPrivateState();
+ if (internal_state != eStateStopped)
+ {
+ if (i < num_commands - 1)
+ {
+ if (out_fh)
+ ::fprintf (out_fh, "Short-circuiting command execution because target state changed to %s."
+ " last command: \"%s\"\n", StateAsCString(internal_state),
+ commands.GetStringAtIndex(i));
+ }
+ break;
+ }
+
+ // First time through we use the context from the stoppoint, after that we use whatever
+ // has been set by the previous command.
+ exe_ctx = Debugger::GetSharedInstance().GetCurrentExecutionContext();
+
+
+ if (out_fh)
+ ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
+ if (err_fh)
+ ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
+ result.Clear();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+
+ if (err_fh && !result.Succeeded() && i < num_commands)
+ ::fprintf (err_fh, "Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i));
+
+ if (out_fh)
+ ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
+
+ if (err_fh)
+ ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
+ }
+ return ret_value;
+}
+
diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.h b/lldb/source/Commands/CommandObjectBreakpointCommand.h
new file mode 100644
index 00000000000..2ba2c6075e8
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectBreakpointCommand.h
@@ -0,0 +1,169 @@
+//===-- 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/Core/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 ();
+
+
+ static bool
+ BreakpointOptionsCallbackFunction (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommandAdd
+//-------------------------------------------------------------------------
+
+
+class CommandObjectBreakpointCommandAdd : public CommandObject
+{
+public:
+
+ CommandObjectBreakpointCommandAdd ();
+
+ virtual
+ ~CommandObjectBreakpointCommandAdd ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual Options *
+ GetOptions ();
+
+ void
+ CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CommandReturnObject &result);
+
+ static size_t
+ GenerateBreakpointCommandCallback (void *baton,
+ InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ static bool
+ BreakpointOptionsCallbackFunction (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions ();
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg);
+
+ void
+ ResetOptionValues ();
+
+ const lldb::OptionDefinition*
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::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;
+ };
+
+private:
+ CommandOptions m_options;
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommandRemove
+//-------------------------------------------------------------------------
+
+class CommandObjectBreakpointCommandRemove : public CommandObject
+{
+public:
+ CommandObjectBreakpointCommandRemove ();
+
+ virtual
+ ~CommandObjectBreakpointCommandRemove ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+private:
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommandList
+//-------------------------------------------------------------------------
+
+class CommandObjectBreakpointCommandList : public CommandObject
+{
+public:
+ CommandObjectBreakpointCommandList ();
+
+ virtual
+ ~CommandObjectBreakpointCommandList ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+private:
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectBreakpointCommand_h_
diff --git a/lldb/source/Commands/CommandObjectCall.cpp b/lldb/source/Commands/CommandObjectCall.cpp
new file mode 100644
index 00000000000..58d0a0e9f11
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectCall.cpp
@@ -0,0 +1,307 @@
+//===-- CommandObjectCall.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectCall.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.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/CommandContext.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/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.
+//
+
+CommandObjectCall::CommandOptions::CommandOptions () :
+ Options()
+{
+ // Keep only one place to reset the values to their defaults
+ ResetOptionValues();
+}
+
+
+CommandObjectCall::CommandOptions::~CommandOptions ()
+{
+}
+
+Error
+CommandObjectCall::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
+{
+ Error error;
+
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'l':
+ if (language.SetLanguageFromCString (option_arg) == false)
+ {
+ error.SetErrorStringWithFormat("Invalid language option argument '%s'.\n", option_arg);
+ }
+ break;
+
+ case 'g':
+ debug = true;
+ break;
+
+ case 'f':
+ error = Args::StringToFormat(option_arg,format);
+ break;
+
+ case 'n':
+ noexecute = true;
+ break;
+
+ case 'a':
+ use_abi = true;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectCall::CommandOptions::ResetOptionValues ()
+{
+ Options::ResetOptionValues();
+ language.Clear();
+ debug = false;
+ format = eFormatDefault;
+ show_types = true;
+ show_summary = true;
+ noexecute = false;
+ use_abi = false;
+}
+
+const lldb::OptionDefinition*
+CommandObjectCall::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+CommandObjectCall::CommandObjectCall () :
+ CommandObject (
+ "call",
+ "Call a function.",
+ "call <return_type> <function-name> [[<arg1-type> <arg1-value>] ... <argn-type> <argn-value>] [<cmd-options>]",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+{
+}
+
+CommandObjectCall::~CommandObjectCall ()
+{
+}
+
+Options *
+CommandObjectCall::GetOptions ()
+{
+ return &m_options;
+}
+
+bool
+CommandObjectCall::Execute
+(
+ Args &command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ ConstString target_triple;
+ int num_args = command.GetArgumentCount();
+
+ Target *target = context->GetTarget ();
+ if (target)
+ target->GetTargetTriple(target_triple);
+
+ if (!target_triple)
+ target_triple = Host::GetTargetTriple ();
+
+ ExecutionContext exe_ctx(context->GetExecutionContext());
+ if (exe_ctx.thread == NULL || exe_ctx.frame == NULL)
+ {
+ result.AppendError ("No currently selected thread and frame.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (num_args < 2)
+ {
+ result.AppendErrorWithFormat ("Invalid usage, should be: %s.\n", GetSyntax());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if ((num_args - 2) %2 != 0)
+ {
+ result.AppendErrorWithFormat ("Invalid usage - unmatched args & types, should be: %s.\n", GetSyntax());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (target_triple)
+ {
+ //const char *return_type = command.GetArgumentAtIndex(0);
+ const char *function_name = command.GetArgumentAtIndex(1);
+ // Look up the called function:
+
+ Function *target_fn = exe_ctx.frame->GetSymbolContext(eSymbolContextEverything).FindFunctionByName (function_name);
+
+ // FIXME: If target_fn is NULL, we should look up the name as a symbol and use it and the provided
+ // return type.
+
+ if (target_fn == NULL)
+ {
+ result.AppendErrorWithFormat ("Could not find function '%s'.\n", function_name);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ValueList value_list;
+ // Okay, now parse arguments. For now we only accept basic types.
+ for (int i = 2; i < num_args; i+= 2)
+ {
+ const char *type_str = command.GetArgumentAtIndex(i);
+ const char *value_str = command.GetArgumentAtIndex(i + 1);
+ bool success;
+ if (strcmp(type_str, "int") == 0
+ || strcmp(type_str, "int32_t") == 0)
+ {
+ value_list.PushValue(Value(Args::StringToSInt32(value_str, 0, 0, &success)));
+ }
+ else if (strcmp (type_str, "int64_t") == 0)
+ {
+ value_list.PushValue(Value(Args::StringToSInt64(value_str, 0, 0, &success)));
+ }
+ else if (strcmp(type_str, "uint") == 0
+ || strcmp(type_str, "uint32_t") == 0)
+ {
+ value_list.PushValue(Value(Args::StringToUInt32(value_str, 0, 0, &success)));
+ }
+ else if (strcmp (type_str, "uint64_t") == 0)
+ {
+ value_list.PushValue(Value(Args::StringToUInt64(value_str, 0, 0, &success)));
+ }
+ else if (strcmp (type_str, "cstr") == 0)
+ {
+ Value val ((intptr_t)value_str);
+ val.SetValueType (Value::eValueTypeHostAddress);
+
+
+ void *cstr_type = target->GetScratchClangASTContext()->GetCStringType(true);
+ val.SetContext (Value::eContextTypeOpaqueClangQualType, cstr_type);
+ value_list.PushValue(val);
+
+ success = true;
+ }
+
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("Could not convert value: '%s' to type '%s'.\n", value_str, type_str);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ // Okay, we have the function and the argument list and the return type. Now make a ClangFunction object and
+ // run it:
+
+ StreamString errors;
+ ClangFunction clang_fun (target_triple.GetCString(), *target_fn, target->GetScratchClangASTContext(), value_list);
+ if (m_options.noexecute)
+ {
+ // Now write down the argument values for this call.
+ lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+ if (!clang_fun.InsertFunction (exe_ctx, args_addr, errors))
+ {
+ result.AppendErrorWithFormat("Error inserting function: '%s'.\n", errors.GetData());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ result.Succeeded();
+ return true;
+ }
+ }
+
+ ClangFunction::ExecutionResults return_status;
+ Value return_value;
+
+ if (m_options.use_abi)
+ {
+ return_status = clang_fun.ExecuteFunctionWithABI(exe_ctx, errors, return_value);
+ }
+ else
+ {
+ bool stop_others = true;
+ return_status = clang_fun.ExecuteFunction(exe_ctx, errors, stop_others, NULL, return_value);
+ }
+
+ // Now figure out what to do with the return value.
+ if (return_status == ClangFunction::eExecutionSetupError)
+ {
+ result.AppendErrorWithFormat("Error setting up function execution: '%s'.\n", errors.GetData());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else if (return_status != ClangFunction::eExecutionCompleted)
+ {
+ result.AppendWarningWithFormat("Interrupted while calling function: '%s'.\n", errors.GetData());
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+ else
+ {
+ // Now print out the result.
+ result.GetOutputStream().Printf("Return value: ");
+ return_value.Dump(&(result.GetOutputStream()));
+ result.Succeeded();
+ }
+
+ }
+ else
+ {
+ result.AppendError ("invalid target triple");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+}
+
+lldb::OptionDefinition
+CommandObjectCall::CommandOptions::g_option_table[] =
+{
+{ 0, true, "language", 'l', required_argument, NULL, 0, "[c|c++|objc|objc++]", "Sets the language to use when parsing the expression."},
+{ 0, false, "format", 'f', required_argument, NULL, 0, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]", "Specify the format that the expression output should use."},
+{ 0, false, "debug", 'g', no_argument, NULL, 0, NULL, "Enable verbose debug logging of the expression parsing and evaluation."},
+{ 0, false, "noexecute", 'n', no_argument, NULL, 0, "no execute", "Only JIT and copy the wrapper & arguments, but don't execute."},
+{ 0, false, "useabi", 'a', no_argument, NULL, 0, NULL, "Use the ABI instead of the JIT to marshall arguments."},
+{ 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
+};
+
diff --git a/lldb/source/Commands/CommandObjectCall.h b/lldb/source/Commands/CommandObjectCall.h
new file mode 100644
index 00000000000..c051a142ece
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectCall.h
@@ -0,0 +1,84 @@
+//===-- CommandObjectCall.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectCall_h_
+#define liblldb_CommandObjectCall_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Core/Language.h"
+
+namespace lldb_private {
+
+class CommandObjectCall : public CommandObject
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions ();
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg);
+
+ void
+ ResetOptionValues ();
+
+ const lldb::OptionDefinition*
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+ Language language;
+ lldb::Encoding encoding;
+ lldb::Format format;
+ bool debug;
+ bool show_types;
+ bool show_summary;
+ bool noexecute;
+ bool use_abi;
+ };
+
+ CommandObjectCall ();
+
+ virtual
+ ~CommandObjectCall ();
+
+ virtual
+ Options *
+ GetOptions ();
+
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual bool
+ WantsRawCommandString() { return false; }
+
+protected:
+
+ CommandOptions m_options;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectCall_h_
diff --git a/lldb/source/Commands/CommandObjectDelete.cpp b/lldb/source/Commands/CommandObjectDelete.cpp
new file mode 100644
index 00000000000..2fc072e2de4
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectDelete.cpp
@@ -0,0 +1,32 @@
+//===-- CommandObjectDelete.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectDelete.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectDelete
+//-------------------------------------------------------------------------
+
+CommandObjectDelete::CommandObjectDelete () :
+CommandObjectCrossref ("delete", "Lists the kinds of objects you can delete, and shows syntax for deleting them.", "delete")
+{
+}
+
+CommandObjectDelete::~CommandObjectDelete ()
+{
+}
+
+
diff --git a/lldb/source/Commands/CommandObjectDelete.h b/lldb/source/Commands/CommandObjectDelete.h
new file mode 100644
index 00000000000..f7d86b7aef7
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectDelete.h
@@ -0,0 +1,37 @@
+//===-- CommandObjectDelete.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectDelete_h_
+#define liblldb_CommandObjectDelete_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectCrossref.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectDelete : public CommandObjectCrossref
+{
+public:
+ CommandObjectDelete ();
+
+ virtual
+ ~CommandObjectDelete ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectDelete_h_
diff --git a/lldb/source/Commands/CommandObjectDisassemble.cpp b/lldb/source/Commands/CommandObjectDisassemble.cpp
new file mode 100644
index 00000000000..0985504e4ff
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectDisassemble.cpp
@@ -0,0 +1,431 @@
+//===-- 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 "CommandObjectDisassemble.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/Args.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#define DEFAULT_DISASM_BYTE_SIZE 32
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandObjectDisassemble::CommandOptions::CommandOptions () :
+ Options(),
+ m_func_name(),
+ m_load_addr()
+{
+ ResetOptionValues();
+}
+
+CommandObjectDisassemble::CommandOptions::~CommandOptions ()
+{
+}
+
+Error
+CommandObjectDisassemble::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
+{
+ Error error;
+
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'm':
+ show_mixed = true;
+ break;
+
+ case 'c':
+ num_lines_context = Args::StringToUInt32(option_arg, 0, 0);
+ break;
+
+ case 'b':
+ show_bytes = true;
+ break;
+
+ case 'a':
+ m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 0);
+ if (m_load_addr == LLDB_INVALID_ADDRESS)
+ m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 16);
+
+ if (m_load_addr == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat ("Invalid address string '%s'.\n", optarg);
+ break;
+
+ case 'n':
+ m_func_name = option_arg;
+ break;
+
+ case 'r':
+ raw = true;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectDisassemble::CommandOptions::ResetOptionValues ()
+{
+ Options::ResetOptionValues();
+ show_mixed = false;
+ show_bytes = false;
+ num_lines_context = 0;
+ m_func_name.clear();
+ m_load_addr = LLDB_INVALID_ADDRESS;
+}
+
+const lldb::OptionDefinition*
+CommandObjectDisassemble::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+lldb::OptionDefinition
+CommandObjectDisassemble::CommandOptions::g_option_table[] =
+{
+{ 0, false, "bytes", 'b', no_argument, NULL, 0, NULL, "Show opcode bytes when disassembling."},
+{ 0, false, "context", 'c', required_argument, NULL, 0, "<num-lines>", "Number of context lines of source to show."},
+{ 0, false, "mixed", 'm', no_argument, NULL, 0, NULL, "Enable mixed source and assembly display."},
+{ 0, false, "raw", 'r', no_argument, NULL, 0, NULL, "Print raw disassembly with no symbol information."},
+
+{ 1, false, "address", 'a', required_argument, NULL, 0, "<address>", "Address to start disassembling."},
+{ 1, false, "bytes", 'b', no_argument, NULL, 0, NULL, "Show opcode bytes when disassembling."},
+{ 1, false, "context", 'c', required_argument, NULL, 0, "<num-lines>", "Number of context lines of source to show."},
+{ 1, false, "mixed", 'm', no_argument, NULL, 0, NULL, "Enable mixed source and assembly display."},
+{ 1, false, "raw", 'r', no_argument, NULL, 0, NULL, "Print raw disassembly with no symbol information."},
+
+{ 2, false, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, "<function-name>", "Disassemble entire contents of the given function name."},
+{ 2, false, "bytes", 'b', no_argument, NULL, 0, NULL, "Show opcode bytes when disassembling."},
+{ 2, false, "context", 'c', required_argument, NULL, 0, "<num-lines>", "Number of context lines of source to show."},
+{ 2, false, "mixed", 'm', no_argument, NULL, 0, NULL, "Enable mixed source and assembly display."},
+{ 2, false, "raw", 'r', no_argument, NULL, 0, NULL, "Print raw disassembly with no symbol information."},
+
+{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+
+//-------------------------------------------------------------------------
+// CommandObjectDisassemble
+//-------------------------------------------------------------------------
+
+CommandObjectDisassemble::CommandObjectDisassemble () :
+ CommandObject ("disassemble",
+ "Disassemble bytes in the current function or anywhere in the inferior program.",
+ "disassemble [[<start-addr> [<end-addr>]] | <function-name>] [<cmd-options>]")
+{
+}
+
+CommandObjectDisassemble::~CommandObjectDisassemble()
+{
+}
+
+void
+CommandObjectDisassemble::Disassemble
+(
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result,
+ Disassembler *disassembler,
+ const SymbolContextList &sc_list
+)
+{
+ const size_t count = sc_list.GetSize();
+ SymbolContext sc;
+ AddressRange range;
+ for (size_t i=0; i<count; ++i)
+ {
+ if (sc_list.GetContextAtIndex(i, sc) == false)
+ break;
+ if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, range))
+ {
+ lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(context->GetExecutionContext().process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ {
+ lldb::addr_t end_addr = addr + range.GetByteSize();
+ Disassemble (context, interpreter, result, disassembler, addr, end_addr);
+ }
+ }
+ }
+}
+
+void
+CommandObjectDisassemble::Disassemble
+(
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result,
+ Disassembler *disassembler,
+ lldb::addr_t addr,
+ lldb::addr_t end_addr
+)
+{
+ if (addr == LLDB_INVALID_ADDRESS)
+ return;
+
+ if (end_addr == LLDB_INVALID_ADDRESS || addr >= end_addr)
+ end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
+
+ ExecutionContext exe_ctx (context->GetExecutionContext());
+ DataExtractor data;
+ size_t bytes_disassembled = disassembler->ParseInstructions (&exe_ctx, eAddressTypeLoad, addr, end_addr - addr, data);
+ if (bytes_disassembled == 0)
+ {
+ // Nothing got disassembled...
+ }
+ else
+ {
+ // We got some things disassembled...
+ size_t num_instructions = disassembler->GetInstructionList().GetSize();
+ uint32_t offset = 0;
+ Stream &output_stream = result.GetOutputStream();
+ SymbolContext sc;
+ SymbolContext prev_sc;
+ AddressRange sc_range;
+ if (m_options.show_mixed)
+ output_stream.IndentMore ();
+
+ for (size_t i=0; i<num_instructions; ++i)
+ {
+ Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i);
+ if (inst)
+ {
+ lldb::addr_t curr_addr = addr + offset;
+ if (m_options.show_mixed)
+ {
+ Process *process = context->GetExecutionContext().process;
+ if (!sc_range.ContainsLoadAddress (curr_addr, process))
+ {
+ prev_sc = sc;
+ Address curr_so_addr;
+ if (process && process->ResolveLoadAddress (curr_addr, curr_so_addr))
+ {
+ if (curr_so_addr.GetSection())
+ {
+ Module *module = curr_so_addr.GetSection()->GetModule();
+ uint32_t resolved_mask = module->ResolveSymbolContextForAddress(curr_so_addr, eSymbolContextEverything, sc);
+ if (resolved_mask)
+ {
+ sc.GetAddressRange (eSymbolContextEverything, sc_range);
+ if (sc != prev_sc)
+ {
+ if (offset != 0)
+ output_stream.EOL();
+
+ sc.DumpStopContext(&output_stream, process, curr_so_addr);
+ output_stream.EOL();
+ if (sc.comp_unit && sc.line_entry.IsValid())
+ {
+ interpreter->GetSourceManager().DisplaySourceLinesWithLineNumbers (
+ sc.line_entry.file,
+ sc.line_entry.line,
+ m_options.num_lines_context,
+ m_options.num_lines_context,
+ m_options.num_lines_context ? "->" : "",
+ &output_stream);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (m_options.show_mixed)
+ output_stream.IndentMore ();
+ output_stream.Indent();
+ size_t inst_byte_size = inst->GetByteSize();
+ inst->Dump(&output_stream, curr_addr, m_options.show_bytes ? &data : NULL, offset, exe_ctx, m_options.raw);
+ output_stream.EOL();
+ offset += inst_byte_size;
+ if (m_options.show_mixed)
+ output_stream.IndentLess ();
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (m_options.show_mixed)
+ output_stream.IndentLess ();
+
+ }
+}
+
+bool
+CommandObjectDisassemble::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, set executable file using 'file' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ArchSpec arch(target->GetArchitecture());
+ if (!arch.IsValid())
+ {
+ result.AppendError ("target needs valid architecure in order to be able to disassemble");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Disassembler *disassembler = Disassembler::FindPlugin(arch);
+
+ if (disassembler == NULL)
+ {
+ result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for %s architecture.\n", arch.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ lldb::addr_t addr = LLDB_INVALID_ADDRESS;
+ lldb::addr_t end_addr = LLDB_INVALID_ADDRESS;
+ ConstString name;
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0 && m_options.m_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ addr = m_options.m_load_addr;
+ end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
+ } else if (argc == 0 && !m_options.m_func_name.empty())
+ {
+ ConstString tmpname(m_options.m_func_name.c_str());
+ name = tmpname;
+ } else if (argc == 0)
+ {
+ ExecutionContext exe_ctx(context->GetExecutionContext());
+ if (exe_ctx.frame)
+ {
+ SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
+ if (sc.function)
+ {
+ addr = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(exe_ctx.process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ end_addr = addr + sc.function->GetAddressRange().GetByteSize();
+ }
+ else if (sc.symbol && sc.symbol->GetAddressRangePtr())
+ {
+ addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetLoadAddress(exe_ctx.process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ {
+ end_addr = addr + sc.symbol->GetAddressRangePtr()->GetByteSize();
+ if (addr == end_addr)
+ end_addr += DEFAULT_DISASM_BYTE_SIZE;
+ }
+ }
+ else
+ {
+ addr = exe_ctx.frame->GetPC().GetLoadAddress(exe_ctx.process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid frame");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else if (argc == 1)
+ {
+ const char *arg = command.GetArgumentAtIndex(0);
+ addr = Args::StringToAddress (arg);
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ // Lookup function or symbol name?
+ ConstString tmpname(arg);
+ name = tmpname;
+ }
+ else
+ {
+ end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
+ }
+ }
+ else if (argc >= 1 && argc <= 2)
+ {
+ addr = Args::StringToAddress (command.GetArgumentAtIndex(0));
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ result.AppendErrorWithFormat ("Unable to parse address '%s'.\n", command.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ end_addr = Args::StringToAddress (command.GetArgumentAtIndex(1), addr);
+ if (end_addr == LLDB_INVALID_ADDRESS)
+ {
+ result.AppendErrorWithFormat ("Unable to parse address '%s'.\n", command.GetArgumentAtIndex(1));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (!name.IsEmpty())
+ {
+ SymbolContextList sc_list;
+
+ if (target->GetImages().FindFunctions(name, sc_list))
+ {
+ Disassemble (context, interpreter, result, disassembler, sc_list);
+ }
+ else if (target->GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeCode, sc_list))
+ {
+ Disassemble (context, interpreter, result, disassembler, sc_list);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (addr < end_addr)
+ {
+ Disassemble (context, interpreter, result, disassembler, addr, end_addr);
+ }
+
+ if (addr == LLDB_INVALID_ADDRESS && name.IsEmpty())
+ {
+ result.AppendError ("No recognizable address of function name provided");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ {
+ return result.Succeeded();
+ }
+}
diff --git a/lldb/source/Commands/CommandObjectDisassemble.h b/lldb/source/Commands/CommandObjectDisassemble.h
new file mode 100644
index 00000000000..2cf800d2f59
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectDisassemble.h
@@ -0,0 +1,95 @@
+//===-- 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/Interpreter/CommandObject.h"
+#include "lldb/Core/Options.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectDisassemble
+//-------------------------------------------------------------------------
+
+class CommandObjectDisassemble : public CommandObject
+{
+public:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions ();
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg);
+
+ void
+ ResetOptionValues ();
+
+ const lldb::OptionDefinition*
+ GetDefinitions ();
+
+ bool show_mixed; // Show mixed source/assembly
+ bool show_bytes;
+ uint32_t num_lines_context;
+ bool raw;
+ std::string m_func_name;
+ lldb::addr_t m_load_addr;
+ static lldb::OptionDefinition g_option_table[];
+ };
+
+ CommandObjectDisassemble ();
+
+ virtual
+ ~CommandObjectDisassemble ();
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+protected:
+ CommandOptions m_options;
+
+ void
+ Disassemble (CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result,
+ Disassembler *disassembler,
+ lldb::addr_t addr,
+ lldb::addr_t end_addr);
+
+ void
+ Disassemble (CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result,
+ Disassembler *disassembler,
+ const SymbolContextList &sc_list);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectDisassemble_h_
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
new file mode 100644
index 00000000000..9afc8c0a1a3
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -0,0 +1,554 @@
+//===-- 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 "CommandObjectExpression.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/CommandContext.h"
+#include "lldb/Interpreter/CommandReturnObject.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 "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandObjectExpression::CommandOptions::CommandOptions () :
+ Options()
+{
+ // Keep only one place to reset the values to their defaults
+ ResetOptionValues();
+}
+
+
+CommandObjectExpression::CommandOptions::~CommandOptions ()
+{
+}
+
+Error
+CommandObjectExpression::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
+{
+ Error error;
+
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'l':
+ if (language.SetLanguageFromCString (option_arg) == false)
+ {
+ error.SetErrorStringWithFormat("Invalid language option argument '%s'.\n", option_arg);
+ }
+ break;
+
+ case 'g':
+ debug = true;
+ break;
+
+ case 'f':
+ error = Args::StringToFormat(option_arg, format);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectExpression::CommandOptions::ResetOptionValues ()
+{
+ Options::ResetOptionValues();
+ language.Clear();
+ debug = false;
+ format = eFormatDefault;
+ show_types = true;
+ show_summary = true;
+}
+
+const lldb::OptionDefinition*
+CommandObjectExpression::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+CommandObjectExpression::CommandObjectExpression () :
+ CommandObject (
+ "expression",
+ "Evaluate a C expression in the current program context, using variables currently in scope.",
+ "expression [<cmd-options>] <expr>"),
+ m_expr_line_count (0),
+ m_expr_lines ()
+{
+ SetHelpLong(
+"Examples: \n\
+\n\
+ expr my_struct->a = my_array[3] \n\
+ expr -f bin -- (index * 8) + 5 \n\
+ expr char c[] = \"foo\"; c[0]\n");
+}
+
+CommandObjectExpression::~CommandObjectExpression ()
+{
+}
+
+Options *
+CommandObjectExpression::GetOptions ()
+{
+ return &m_options;
+}
+
+
+bool
+CommandObjectExpression::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ return false;
+}
+
+
+size_t
+CommandObjectExpression::MultiLineExpressionCallback
+(
+ void *baton,
+ InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle();
+ CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ if (out_fh)
+ ::fprintf (out_fh, "%s\n", "Enter expressions, then terminate with an empty line to evaluate:");
+ // Fall through
+ case eInputReaderReactivate:
+ //if (out_fh)
+ // ::fprintf (out_fh, "%3u: ", cmd_object_expr->m_expr_line_count);
+ break;
+
+ case eInputReaderDeactivate:
+ 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);
+ //else if (out_fh && !reader->IsDone())
+ // ::fprintf (out_fh, "%3u: ", cmd_object_expr->m_expr_line_count);
+ break;
+
+ case eInputReaderDone:
+ {
+ StreamFile out_stream(Debugger::GetSharedInstance().GetOutputFileHandle());
+ StreamFile err_stream(Debugger::GetSharedInstance().GetErrorFileHandle());
+ bool bare = false;
+ cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
+ bare,
+ out_stream,
+ err_stream);
+ }
+ break;
+ }
+
+ return bytes_len;
+}
+
+bool
+CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream &output_stream, Stream &error_stream)
+{
+ bool success = false;
+ ConstString target_triple;
+ Target *target = m_exe_ctx.target;
+ if (target)
+ target->GetTargetTriple(target_triple);
+
+ if (!target_triple)
+ target_triple = Host::GetTargetTriple ();
+
+
+ if (target_triple)
+ {
+ const bool show_types = m_options.show_types;
+ const bool show_summary = m_options.show_summary;
+ const bool debug = m_options.debug;
+
+ ClangExpressionDeclMap expr_decl_map(&m_exe_ctx);
+ ClangExpression clang_expr(target_triple.AsCString(), &expr_decl_map);
+
+ unsigned num_errors = 0;
+
+ if (bare)
+ num_errors = clang_expr.ParseBareExpression (llvm::StringRef(expr), error_stream);
+ else
+ num_errors = clang_expr.ParseExpression (expr, error_stream);
+
+ if (num_errors == 0)
+ {
+ StreamString dwarf_opcodes;
+ dwarf_opcodes.SetByteOrder(eByteOrderHost);
+ dwarf_opcodes.GetFlags().Set(Stream::eBinary);
+ ClangExpressionVariableList expr_local_vars;
+ clang_expr.ConvertExpressionToDWARF (expr_local_vars, dwarf_opcodes);
+
+ success = true;
+
+ DataExtractor dwarf_opcodes_data(dwarf_opcodes.GetData(), dwarf_opcodes.GetSize(), eByteOrderHost, 8);
+ DWARFExpression expr(dwarf_opcodes_data, 0, dwarf_opcodes_data.GetByteSize(), NULL);
+ expr.SetExpressionLocalVariableList(&expr_local_vars);
+ if (debug)
+ {
+ output_stream << "Expression parsed ok, dwarf opcodes:";
+ output_stream.IndentMore();
+ expr.GetDescription(&output_stream, lldb::eDescriptionLevelVerbose);
+ output_stream.IndentLess();
+ output_stream.EOL();
+ }
+
+ clang::ASTContext *ast_context = clang_expr.GetASTContext();
+ Value expr_result;
+ Error expr_error;
+ bool expr_success = expr.Evaluate (&m_exe_ctx, ast_context, NULL, expr_result, &expr_error);
+ if (expr_success)
+ {
+ lldb::Format format = m_options.format;
+
+ // Resolve any values that are possible
+ expr_result.ResolveValue(&m_exe_ctx, ast_context);
+
+ if (expr_result.GetContextType() == Value::eContextTypeInvalid &&
+ expr_result.GetValueType() == Value::eValueTypeScalar &&
+ format == eFormatDefault)
+ {
+ // The expression result is just a scalar with no special formatting
+ expr_result.GetScalar().GetValue (&output_stream, show_types);
+ output_stream.EOL();
+ }
+ else
+ {
+ DataExtractor data;
+ expr_error = expr_result.GetValueAsData (&m_exe_ctx, ast_context, data, 0);
+ if (expr_error.Success())
+ {
+ if (format == eFormatDefault)
+ format = expr_result.GetValueDefaultFormat ();
+
+ void *clang_type = expr_result.GetValueOpaqueClangQualType();
+ if (clang_type)
+ {
+ if (show_types)
+ Type::DumpClangTypeName(&output_stream, clang_type);
+
+ Type::DumpValue (
+ &m_exe_ctx, // The execution context for memory and variable access
+ ast_context, // The ASTContext that the clang type belongs to
+ clang_type, // The opaque clang type we want to dump that value of
+ &output_stream, // Stream to dump to
+ format, // Format to use when dumping
+ data, // A buffer containing the bytes for the clang type
+ 0, // Byte offset within "data" where value is
+ data.GetByteSize(), // Size in bytes of the value we are dumping
+ 0, // Bitfield bit size
+ 0, // Bitfield bit offset
+ show_types, // Show types?
+ show_summary, // Show summary?
+ debug, // Debug logging output?
+ UINT32_MAX); // Depth to dump in case this is an aggregate type
+ }
+ else
+ {
+ data.Dump(&output_stream, // Stream to dump to
+ 0, // Byte offset within "data"
+ format, // Format to use when dumping
+ data.GetByteSize(), // Size in bytes of each item we are dumping
+ 1, // Number of items to dump
+ UINT32_MAX, // Number of items per line
+ LLDB_INVALID_ADDRESS, // Invalid address, don't show any offset/address context
+ 0, // Bitfield bit size
+ 0); // Bitfield bit offset
+ }
+ output_stream.EOL();
+ }
+ else
+ {
+ error_stream.Printf ("error: %s\n", expr_error.AsCString());
+ success = false;
+ }
+ }
+ }
+ else
+ {
+ error_stream.Printf ("error: %s\n", expr_error.AsCString());
+ }
+ }
+ }
+ else
+ {
+ error_stream.PutCString ("error: invalid target triple\n");
+ }
+
+ return success;
+}
+
+bool
+CommandObjectExpression::ExecuteRawCommandString
+(
+ const char *command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ ConstString target_triple;
+ Target *target = context->GetTarget ();
+ if (target)
+ target->GetTargetTriple(target_triple);
+
+ if (!target_triple)
+ target_triple = Host::GetTargetTriple ();
+
+ ExecutionContext exe_ctx(context->GetExecutionContext());
+
+ Stream &output_stream = result.GetOutputStream();
+
+ m_options.ResetOptionValues();
+
+ const char * expr = NULL;
+
+ if (command[0] == '\0')
+ {
+ m_expr_lines.clear();
+ m_expr_line_count = 0;
+
+ InputReaderSP reader_sp (new InputReader());
+ 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())
+ {
+ Debugger::GetSharedInstance().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, interpreter, result))
+ return false;
+ }
+ }
+
+ const bool show_types = m_options.show_types;
+ const bool show_summary = m_options.show_summary;
+ const bool debug = m_options.debug;
+
+
+ if (expr == NULL)
+ expr = command;
+
+ if (target_triple)
+ {
+ ClangExpressionDeclMap expr_decl_map(&exe_ctx);
+
+ ClangExpression clang_expr(target_triple.AsCString(), &expr_decl_map);
+
+ unsigned num_errors = clang_expr.ParseExpression (expr, result.GetErrorStream());
+
+ if (num_errors == 0)
+ {
+ StreamString dwarf_opcodes;
+ dwarf_opcodes.SetByteOrder(eByteOrderHost);
+ dwarf_opcodes.GetFlags().Set(Stream::eBinary);
+ ClangExpressionVariableList expr_local_vars;
+ clang_expr.ConvertExpressionToDWARF (expr_local_vars, dwarf_opcodes);
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ DataExtractor dwarf_opcodes_data(dwarf_opcodes.GetData(), dwarf_opcodes.GetSize(), eByteOrderHost, 8);
+ DWARFExpression expr(dwarf_opcodes_data, 0, dwarf_opcodes_data.GetByteSize(), NULL);
+ expr.SetExpressionLocalVariableList(&expr_local_vars);
+ expr.SetExpressionDeclMap(&expr_decl_map);
+ if (debug)
+ {
+ output_stream << "Expression parsed ok, dwarf opcodes:";
+ output_stream.IndentMore();
+ expr.GetDescription(&output_stream, lldb::eDescriptionLevelVerbose);
+ output_stream.IndentLess();
+ output_stream.EOL();
+ }
+
+ clang::ASTContext *ast_context = clang_expr.GetASTContext();
+ Value expr_result;
+ Error expr_error;
+ bool expr_success = expr.Evaluate (&exe_ctx, ast_context, NULL, expr_result, &expr_error);
+ if (expr_success)
+ {
+ lldb::Format format = m_options.format;
+
+ // Resolve any values that are possible
+ expr_result.ResolveValue(&exe_ctx, ast_context);
+
+ if (expr_result.GetContextType() == Value::eContextTypeInvalid &&
+ expr_result.GetValueType() == Value::eValueTypeScalar &&
+ format == eFormatDefault)
+ {
+ // The expression result is just a scalar with no special formatting
+ expr_result.GetScalar().GetValue (&output_stream, show_types);
+ output_stream.EOL();
+ }
+ else
+ {
+ DataExtractor data;
+ expr_error = expr_result.GetValueAsData (&exe_ctx, ast_context, data, 0);
+ if (expr_error.Success())
+ {
+ if (format == eFormatDefault)
+ format = expr_result.GetValueDefaultFormat ();
+
+ void *clang_type = expr_result.GetValueOpaqueClangQualType();
+ if (clang_type)
+ {
+ if (show_types)
+ Type::DumpClangTypeName(&output_stream, clang_type);
+
+ Type::DumpValue (
+ &exe_ctx, // The execution context for memory and variable access
+ ast_context, // The ASTContext that the clang type belongs to
+ clang_type, // The opaque clang type we want to dump that value of
+ &output_stream, // Stream to dump to
+ format, // Format to use when dumping
+ data, // A buffer containing the bytes for the clang type
+ 0, // Byte offset within "data" where value is
+ data.GetByteSize(), // Size in bytes of the value we are dumping
+ 0, // Bitfield bit size
+ 0, // Bitfield bit offset
+ show_types, // Show types?
+ show_summary, // Show summary?
+ debug, // Debug logging output?
+ UINT32_MAX); // Depth to dump in case this is an aggregate type
+ }
+ else
+ {
+ data.Dump(&output_stream, // Stream to dump to
+ 0, // Byte offset within "data"
+ format, // Format to use when dumping
+ data.GetByteSize(), // Size in bytes of each item we are dumping
+ 1, // Number of items to dump
+ UINT32_MAX, // Number of items per line
+ LLDB_INVALID_ADDRESS, // Invalid address, don't show any offset/address context
+ 0, // Bitfield bit size
+ 0); // Bitfield bit offset
+ }
+ output_stream.EOL();
+ }
+ else
+ {
+ result.AppendError(expr_error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ result.AppendError (expr_error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid target triple");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+}
+
+lldb::OptionDefinition
+CommandObjectExpression::CommandOptions::g_option_table[] =
+{
+{ 0, true, "language", 'l', required_argument, NULL, 0, "[c|c++|objc|objc++]", "Sets the language to use when parsing the expression."},
+{ 0, false, "format", 'f', required_argument, NULL, 0, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]", "Specify the format that the expression output should use."},
+{ 0, false, "debug", 'g', no_argument, NULL, 0, NULL, "Enable verbose debug logging of the expression parsing and evaluation."},
+{ 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
+};
+
diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h
new file mode 100644
index 00000000000..c67ba745af2
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectExpression.h
@@ -0,0 +1,105 @@
+//===-- 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/Core/Options.h"
+#include "lldb/Core/Language.h"
+#include "lldb/Target/ExecutionContext.h"
+
+namespace lldb_private {
+
+class CommandObjectExpression : public CommandObject
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions ();
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg);
+
+ void
+ ResetOptionValues ();
+
+ const lldb::OptionDefinition*
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+ Language language;
+ lldb::Encoding encoding;
+ lldb::Format format;
+ bool debug;
+ bool show_types;
+ bool show_summary;
+ };
+
+ CommandObjectExpression ();
+
+ virtual
+ ~CommandObjectExpression ();
+
+ virtual
+ Options *
+ GetOptions ();
+
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual bool
+ WantsRawCommandString() { return true; }
+
+ virtual bool
+ ExecuteRawCommandString (const char *command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+protected:
+
+ static size_t
+ MultiLineExpressionCallback (void *baton,
+ InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ bool
+ EvaluateExpression (const char *expr,
+ bool bare,
+ Stream &output_stream,
+ Stream &error_stream);
+
+ CommandOptions m_options;
+ ExecutionContext m_exe_ctx;
+ 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/lldb/source/Commands/CommandObjectFile.cpp b/lldb/source/Commands/CommandObjectFile.cpp
new file mode 100644
index 00000000000..01576c5b6d5
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectFile.cpp
@@ -0,0 +1,170 @@
+//===-- CommandObjectFile.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectFile.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Interpreter/CommandContext.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandObjectFile::CommandOptions::CommandOptions() :
+ Options (),
+ m_arch () // Breakpoint info defaults to brief descriptions
+{
+ BuildValidOptionSets();
+}
+
+CommandObjectFile::CommandOptions::~CommandOptions ()
+{
+}
+
+lldb::OptionDefinition
+CommandObjectFile::CommandOptions::g_option_table[] =
+{
+ { 0, false, "arch", 'a', required_argument, NULL, 0, "<arch>", "Specify the architecture to launch."},
+ { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+const lldb::OptionDefinition *
+CommandObjectFile::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+Error
+CommandObjectFile::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
+{
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ {
+ ArchSpec option_arch (option_arg);
+ if (option_arch.IsValid())
+ m_arch = option_arch;
+ else
+ error.SetErrorStringWithFormat ("Invalid arch string '%s'.\n", optarg);
+ }
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectFile::CommandOptions::ResetOptionValues ()
+{
+ Options::ResetOptionValues();
+ m_arch.Clear();
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectFile
+//-------------------------------------------------------------------------
+
+CommandObjectFile::CommandObjectFile() :
+ CommandObject ("file",
+ "Sets the file to be used as the main executable by the debugger.",
+ "file [<cmd-options>] <filename>")
+{
+}
+
+CommandObjectFile::~CommandObjectFile ()
+{
+}
+
+Options *
+CommandObjectFile::GetOptions ()
+{
+ return &m_options;
+}
+
+bool
+CommandObjectFile::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ const char *file_path = command.GetArgumentAtIndex(0);
+ Timer scoped_timer(__PRETTY_FUNCTION__, "(dbg) file '%s'", file_path);
+ const int argc = command.GetArgumentCount();
+ if (argc == 1)
+ {
+ FileSpec file_spec (file_path);
+
+ if (! file_spec.Exists())
+ {
+ result.AppendErrorWithFormat ("File '%s' does not exist.\n", file_path);
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ TargetSP target_sp;
+
+ ArchSpec arch;
+ if (m_options.m_arch.IsValid())
+ arch = m_options.m_arch;
+ else
+ {
+ arch = lldb_private::GetDefaultArchitecture ();
+ if (!arch.IsValid())
+ arch = LLDB_ARCH_DEFAULT;
+ }
+
+ Error error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file_spec, arch, NULL, true, target_sp);
+
+ if (error.Fail() && !m_options.m_arch.IsValid())
+ {
+ if (arch == LLDB_ARCH_DEFAULT_32BIT)
+ arch = LLDB_ARCH_DEFAULT_64BIT;
+ else
+ arch = LLDB_ARCH_DEFAULT_32BIT;
+ error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file_spec, arch, NULL, true, target_sp);
+ }
+
+ if (target_sp)
+ {
+ Debugger::GetSharedInstance().GetTargetList().SetCurrentTarget(target_sp.get());
+ result.AppendMessageWithFormat ("Current executable set to '%s' (%s).\n", file_path, arch.AsCString());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes exactly one executable path argument.\n", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+
+}
diff --git a/lldb/source/Commands/CommandObjectFile.h b/lldb/source/Commands/CommandObjectFile.h
new file mode 100644
index 00000000000..c44f610d970
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectFile.h
@@ -0,0 +1,79 @@
+//===-- CommandObjectFile.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectFile_h_
+#define liblldb_CommandObjectFile_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Options.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectFile
+//-------------------------------------------------------------------------
+
+class CommandObjectFile : public CommandObject
+{
+public:
+
+ CommandObjectFile ();
+
+ virtual
+ ~CommandObjectFile ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual Options *
+ GetOptions ();
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions ();
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg);
+
+ void
+ ResetOptionValues ();
+
+ const lldb::OptionDefinition*
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ ArchSpec m_arch;
+ };
+
+private:
+ CommandOptions m_options;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectFile_h_
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
new file mode 100644
index 00000000000..78682dc0ca3
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -0,0 +1,171 @@
+//===-- 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 "CommandObjectFrame.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Interpreter/CommandContext.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+
+#include "CommandObjectThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#pragma mark CommandObjectFrameInfo
+
+//-------------------------------------------------------------------------
+// CommandObjectFrameInfo
+//-------------------------------------------------------------------------
+
+class CommandObjectFrameInfo : public CommandObject
+{
+public:
+
+ CommandObjectFrameInfo () :
+ CommandObject ("frame info",
+ "Lists information about the currently selected frame in the current thread.",
+ "frame info",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+ {
+ }
+
+ ~CommandObjectFrameInfo ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ ExecutionContext exe_ctx(context->GetExecutionContext());
+ if (exe_ctx.frame)
+ {
+ exe_ctx.frame->Dump (&result.GetOutputStream(), true);
+ result.GetOutputStream().EOL();
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("no current frame");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectFrameSelect
+
+//-------------------------------------------------------------------------
+// CommandObjectFrameSelect
+//-------------------------------------------------------------------------
+
+class CommandObjectFrameSelect : public CommandObject
+{
+public:
+
+ CommandObjectFrameSelect () :
+ CommandObject ("frame select",
+ "Select the current frame by index in the current thread.",
+ "frame select <frame-index>",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+ {
+ }
+
+ ~CommandObjectFrameSelect ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ ExecutionContext exe_ctx (context->GetExecutionContext());
+ if (exe_ctx.thread)
+ {
+ if (command.GetArgumentCount() == 1)
+ {
+ const char *frame_idx_cstr = command.GetArgumentAtIndex(0);
+
+ const uint32_t num_frames = exe_ctx.thread->GetStackFrameCount();
+ const uint32_t frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0);
+ if (frame_idx < num_frames)
+ {
+ exe_ctx.thread->SetCurrentFrameByIndex (frame_idx);
+ exe_ctx.frame = exe_ctx.thread->GetCurrentFrame ().get();
+
+ if (exe_ctx.frame)
+ {
+ if (DisplayFrameForExecutionContext (exe_ctx.thread,
+ exe_ctx.frame,
+ interpreter,
+ result.GetOutputStream(),
+ true,
+ true,
+ 3,
+ 3))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+ }
+ }
+ if (frame_idx == UINT32_MAX)
+ result.AppendErrorWithFormat ("Invalid frame index: %s.\n", frame_idx_cstr);
+ else
+ result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx);
+ }
+ else
+ {
+ result.AppendError ("invalid arguments");
+ result.AppendErrorWithFormat ("Usage: %s\n", m_cmd_syntax.c_str());
+ }
+ }
+ else
+ {
+ result.AppendError ("no current thread");
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+};
+
+#pragma mark CommandObjectMultiwordFrame
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordFrame
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter *interpreter) :
+ CommandObjectMultiword ("frame",
+ "A set of commands for operating on the current thread's frames.",
+ "frame <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand (CommandObjectSP (new CommandObjectFrameInfo ()), "info", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectFrameSelect ()), "select", interpreter);
+}
+
+CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame ()
+{
+}
+
diff --git a/lldb/source/Commands/CommandObjectFrame.h b/lldb/source/Commands/CommandObjectFrame.h
new file mode 100644
index 00000000000..cb9cafe3a74
--- /dev/null
+++ b/lldb/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/Core/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/lldb/source/Commands/CommandObjectHelp.cpp b/lldb/source/Commands/CommandObjectHelp.cpp
new file mode 100644
index 00000000000..35e5b2ee5c4
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectHelp.cpp
@@ -0,0 +1,266 @@
+//===-- 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 "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/Core/Options.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectHelp
+//-------------------------------------------------------------------------
+
+CommandObjectHelp::CommandObjectHelp () :
+ CommandObject ("help",
+ "Shows a list of all debugger commands, or give details about specific commands.",
+ "help [<cmd-name>]")
+{
+}
+
+CommandObjectHelp::~CommandObjectHelp()
+{
+}
+
+
+bool
+CommandObjectHelp::OldExecute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ CommandObject::CommandMap::iterator pos;
+ CommandObject *cmd_obj;
+
+ const int argc = command.GetArgumentCount();
+ if (argc > 0)
+ {
+ cmd_obj = interpreter->GetCommandObject (command.GetArgumentAtIndex(0), false, false);
+ if (cmd_obj == NULL)
+ {
+ cmd_obj = interpreter->GetCommandObject (command.GetArgumentAtIndex(0), true, false);
+ if (cmd_obj != NULL)
+ {
+ StreamString alias_help_str;
+ interpreter->GetAliasHelp (command.GetArgumentAtIndex(0), cmd_obj->GetCommandName(), alias_help_str);
+ result.AppendMessageWithFormat ("'%s' is an alias for %s.\n", command.GetArgumentAtIndex (0),
+ alias_help_str.GetData());
+ }
+ }
+
+ if (cmd_obj)
+ {
+ Stream &output_strm = result.GetOutputStream();
+ if (cmd_obj->GetOptions() != NULL)
+ {
+ const char * long_help = cmd_obj->GetHelpLong();
+ if ((long_help!= NULL)
+ && strlen (long_help) > 0)
+ output_strm.Printf ("\n%s", cmd_obj->GetHelpLong());
+ else
+ output_strm.Printf ("\n%s\n", cmd_obj->GetHelp());
+ output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax());
+ cmd_obj->GetOptions()->GenerateOptionUsage (output_strm, cmd_obj);
+ }
+ else if (cmd_obj->IsMultiwordObject())
+ {
+ bool done = false;
+ if (argc > 1)
+ {
+ CommandObject::CommandMap::iterator pos;
+ std::string sub_command = command.GetArgumentAtIndex(1);
+ pos = ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict.find(sub_command);
+ if (pos != ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict.end())
+ {
+ CommandObject *sub_cmd_obj = pos->second.get();
+ if (sub_cmd_obj->GetOptions() != NULL)
+ {
+ output_strm.Printf ("\n%s\n", sub_cmd_obj->GetHelp());
+ output_strm.Printf ("\nSyntax: %s\n", sub_cmd_obj->GetSyntax());
+ sub_cmd_obj->GetOptions()->GenerateOptionUsage (output_strm, sub_cmd_obj);
+ done = true;
+ }
+ else
+ {
+ output_strm.Printf ("\n%s\n", sub_cmd_obj->GetHelp());
+ output_strm.Printf ("\nSyntax: %s\n", sub_cmd_obj->GetSyntax());
+ done = true;
+ }
+ }
+ }
+ if (!done)
+ {
+ output_strm.Printf ("%s\n", cmd_obj->GetHelp());
+ ((CommandObjectMultiword *) cmd_obj)->GenerateHelpText (result, interpreter);
+ }
+ }
+ else
+ {
+ const char *long_help = cmd_obj->GetHelpLong();
+ if ((long_help != NULL)
+ && (strlen (long_help) > 0))
+ output_strm.Printf ("\n%s", cmd_obj->GetHelpLong());
+ else
+ output_strm.Printf ("\n%s\n", cmd_obj->GetHelp());
+ output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax());
+ }
+ 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);
+ }
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ interpreter->GetHelp(result);
+ }
+ return result.Succeeded();
+}
+
+bool
+CommandObjectHelp::Execute (Args &command, CommandContext *context, CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+{
+ CommandObject::CommandMap::iterator pos;
+ CommandObject *cmd_obj;
+ const int argc = command.GetArgumentCount ();
+
+ // 'help' doesn't take any options or arguments, other than command names. If argc is 0, we show the user
+ // all commands and aliases. Otherwise every argument must be the name of a command or a sub-command.
+
+ if (argc == 0)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ interpreter->GetHelp (result); // General help, for ALL commands.
+ }
+ else
+ {
+ // Get command object for the first command argument. Only search built-in command dictionary.
+ cmd_obj = interpreter->GetCommandObject (command.GetArgumentAtIndex (0), false, false);
+ if (cmd_obj == NULL)
+ {
+ // That failed, so now search in the aliases dictionary, too.
+ cmd_obj = interpreter->GetCommandObject (command.GetArgumentAtIndex (0), true, false);
+ }
+
+ if (cmd_obj != NULL)
+ {
+ 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 (int i = 1; i < argc && all_okay; ++i)
+ {
+ std::string sub_command = command.GetArgumentAtIndex(i);
+ if (! sub_cmd_obj->IsMultiwordObject ())
+ {
+ all_okay = false;
+ }
+ else
+ {
+ pos = ((CommandObjectMultiword *) sub_cmd_obj)->m_subcommand_dict.find (sub_command);
+ if (pos != ((CommandObjectMultiword *) sub_cmd_obj)->m_subcommand_dict.end())
+ sub_cmd_obj = pos->second.get();
+ else
+ all_okay = false;
+ }
+ }
+
+ if (!all_okay || (sub_cmd_obj == NULL))
+ {
+ std::string cmd_string;
+ command.GetCommandString (cmd_string);
+ result.AppendErrorWithFormat
+ ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n",
+ cmd_string.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ Stream &output_strm = result.GetOutputStream();
+ if (sub_cmd_obj->GetOptions() != NULL)
+ {
+ output_strm.Printf ("%s\n", sub_cmd_obj->GetHelp());
+ output_strm.Printf ("\nSyntax: %s\n", sub_cmd_obj->GetSyntax());
+ sub_cmd_obj->GetOptions()->GenerateOptionUsage (output_strm, sub_cmd_obj);
+ const char *long_help = sub_cmd_obj->GetHelpLong();
+ if ((long_help != NULL)
+ && (strlen (long_help) > 0))
+ output_strm.Printf ("\n%s", long_help);
+ }
+ else if (sub_cmd_obj->IsMultiwordObject())
+ {
+ output_strm.Printf ("%s\n", sub_cmd_obj->GetHelp());
+ ((CommandObjectMultiword *) sub_cmd_obj)->GenerateHelpText (result, interpreter);
+ }
+ else
+ {
+ const char *long_help = sub_cmd_obj->GetHelpLong();
+ if ((long_help != NULL)
+ && (strlen (long_help) > 0))
+ output_strm.Printf ("%s", long_help);
+ else
+ output_strm.Printf ("%s\n", sub_cmd_obj->GetHelp());
+ output_strm.Printf ("\nSyntax: %s\n", sub_cmd_obj->GetSyntax());
+ }
+ }
+ }
+ 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,
+ CommandInterpreter *interpreter,
+ StringList &matches
+)
+{
+ // Return the completions of the commands in the help system:
+ if (cursor_index == 0)
+ {
+ return interpreter->HandleCompletionMatches(input, cursor_index, cursor_char_position, match_start_point, max_return_elements, matches);
+ }
+ else
+ {
+ CommandObject *cmd_obj = interpreter->GetCommandObject (input.GetArgumentAtIndex(0), true, false);
+ input.Shift();
+ cursor_index--;
+ return cmd_obj->HandleCompletion (input, cursor_index, cursor_char_position, match_start_point, max_return_elements, interpreter, matches);
+ }
+}
diff --git a/lldb/source/Commands/CommandObjectHelp.h b/lldb/source/Commands/CommandObjectHelp.h
new file mode 100644
index 00000000000..a8084aa704d
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectHelp.h
@@ -0,0 +1,59 @@
+//===-- 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"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectHelp
+//-------------------------------------------------------------------------
+
+class CommandObjectHelp : public CommandObject
+{
+public:
+
+ CommandObjectHelp ();
+
+ virtual
+ ~CommandObjectHelp ();
+
+ bool
+ OldExecute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual int
+ HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ StringList &matches);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectHelp_h_
diff --git a/lldb/source/Commands/CommandObjectImage.cpp b/lldb/source/Commands/CommandObjectImage.cpp
new file mode 100644
index 00000000000..ab728e9d32d
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectImage.cpp
@@ -0,0 +1,1419 @@
+//===-- CommandObjectImage.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectImage.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Interpreter/CommandContext.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Static Helper functions
+//----------------------------------------------------------------------
+static void
+DumpModuleArchitecture (Stream &strm, Module *module, uint32_t width)
+{
+ if (module)
+ {
+ if (width)
+ strm.Printf("%-*s", width, module->GetArchitecture().AsCString());
+ else
+ strm.PutCString(module->GetArchitecture().AsCString());
+ }
+}
+
+static void
+DumpModuleUUID (Stream &strm, Module *module)
+{
+ module->GetUUID().Dump (&strm);
+}
+
+static uint32_t
+DumpCompileUnitLineTable
+(
+ CommandContext *context,
+ 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 " << *dynamic_cast<FileSpec*> (sc.comp_unit) << " in `"
+ << module->GetFileSpec().GetFilename() << "\n";
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+ if (line_table)
+ line_table->GetDescription (&strm, context->GetExecutionContext().process, 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)
+ {
+ char fullpath[PATH_MAX];
+ if (file_spec_ptr->GetPath(fullpath, sizeof(fullpath)))
+ {
+ strm.Printf("%-*s", width, fullpath);
+ 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 (CommandContext *context, Stream &strm, Module *module)
+{
+ if (module)
+ {
+ ObjectFile *objfile = module->GetObjectFile ();
+ if (objfile)
+ {
+ Symtab *symtab = objfile->GetSymtab();
+ if (symtab)
+ symtab->Dump(&strm, context->GetExecutionContext().process);
+ }
+ }
+}
+
+static void
+DumpModuleSections (CommandContext *context, Stream &strm, Module *module)
+{
+ if (module)
+ {
+ ObjectFile *objfile = module->GetObjectFile ();
+ if (objfile)
+ {
+ SectionList *section_list = objfile->GetSectionList();
+ if (section_list)
+ section_list->Dump(&strm, context->GetExecutionContext().process, true);
+ }
+ }
+}
+
+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 bool
+LookupAddressInModule (CommandContext *context, Stream &strm, Module *module, uint32_t resolve_mask, lldb::addr_t raw_addr, lldb::addr_t offset)
+{
+ if (module)
+ {
+ lldb::addr_t addr = raw_addr - offset;
+ Address so_addr;
+ SymbolContext sc;
+ Process *process = context->GetExecutionContext().process;
+ if (process && process->IsAlive())
+ {
+ if (!process->ResolveLoadAddress (addr, so_addr))
+ return false;
+ else if (so_addr.GetModule() != module)
+ return false;
+ }
+ else
+ {
+ if (!module->ResolveFileAddress (addr, so_addr))
+ return false;
+ }
+
+ // If an offset was given, print out the address we ended up looking up
+ if (offset)
+ strm.Printf("0x%llx: ", addr);
+
+ ExecutionContextScope *exe_scope = context->GetExecutionContext().GetBestExecutionContextScope();
+ if (so_addr.Dump (&strm, exe_scope, Address::DumpStyleSectionNameOffset))
+ strm.PutCString(": ");
+ so_addr.Dump (&strm, exe_scope, Address::DumpStyleResolvedDescription);
+ return true;
+ }
+
+ return false;
+}
+
+static uint32_t
+LookupSymbolInModule (CommandContext *context, Stream &strm, Module *module, const char *name, bool name_is_regex)
+{
+ if (module)
+ {
+ SymbolContext sc;
+
+ ObjectFile *objfile = module->GetObjectFile ();
+ if (objfile)
+ {
+ Symtab *symtab = objfile->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]);
+ strm.Indent ();
+ symbol->Dump (&strm, context->GetExecutionContext().process, i);
+ }
+ strm.IndentLess ();
+ return num_matches;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+static void
+DumpSymbolContextList (CommandContext *context, Stream &strm, SymbolContextList &sc_list, bool prepend_addr)
+{
+ 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))
+ {
+ strm.Indent();
+ if (prepend_addr)
+ {
+ if (sc.line_entry.range.GetBaseAddress().IsValid())
+ {
+ lldb::addr_t vm_addr =
+ sc.line_entry.range.GetBaseAddress().GetLoadAddress(context->GetExecutionContext().process);
+ int addr_size = sizeof (addr_t);
+ Process *process = context->GetExecutionContext().process;
+ if (process)
+ addr_size = process->GetAddressByteSize();
+ if (vm_addr != LLDB_INVALID_ADDRESS)
+ strm.Address (vm_addr, addr_size);
+ else
+ sc.line_entry.range.GetBaseAddress().Dump (&strm, NULL, Address::DumpStyleSectionNameOffset);
+
+ strm.PutCString(" in ");
+ }
+ }
+ sc.DumpStopContext(&strm, context->GetExecutionContext().process, sc.line_entry.range.GetBaseAddress());
+ }
+ }
+ strm.IndentLess ();
+}
+
+static uint32_t
+LookupFunctionInModule (CommandContext *context, Stream &strm, Module *module, const char *name, bool name_is_regex)
+{
+ if (module && name && name[0])
+ {
+ SymbolContextList sc_list;
+
+ SymbolVendor *symbol_vendor = module->GetSymbolVendor();
+ if (symbol_vendor)
+ {
+ uint32_t num_matches = 0;
+ if (name_is_regex)
+ {
+ RegularExpression function_name_regex (name);
+ num_matches = symbol_vendor->FindFunctions(function_name_regex, true, sc_list);
+
+ }
+ else
+ {
+ ConstString function_name(name);
+ num_matches = symbol_vendor->FindFunctions(function_name, true, sc_list);
+ }
+
+ if (num_matches)
+ {
+ strm.Indent ();
+ strm.Printf("%u match%s found in ", num_matches, num_matches > 1 ? "es" : "");
+ DumpFullpath (strm, &module->GetFileSpec(), 0);
+ strm.PutCString(":\n");
+ DumpSymbolContextList (context, strm, sc_list, true);
+ }
+ return num_matches;
+ }
+ }
+ return 0;
+}
+
+static uint32_t
+LookupFileAndLineInModule (CommandContext *context, Stream &strm, Module *module, const FileSpec &file_spec, uint32_t line, bool check_inlines)
+{
+ 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 (context, strm, sc_list, true);
+ return num_matches;
+ }
+ }
+ return 0;
+
+}
+
+
+//----------------------------------------------------------------------
+// Image symbol table dumping command
+//----------------------------------------------------------------------
+
+class CommandObjectImageDumpModuleList : public CommandObject
+{
+public:
+
+ CommandObjectImageDumpModuleList (const char *name,
+ const char *help,
+ const char *syntax) :
+ CommandObject (name, help, syntax)
+ {
+ }
+
+ virtual
+ ~CommandObjectImageDumpModuleList ()
+ {
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ StringList &matches)
+ {
+ // Arguments are the standard module completer.
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (CommandCompletions::eModuleCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ interpreter,
+ NULL,
+ matches);
+ return matches.GetSize();
+ }
+};
+
+class CommandObjectImageDumpSourceFileList : public CommandObject
+{
+public:
+
+ CommandObjectImageDumpSourceFileList (const char *name,
+ const char *help,
+ const char *syntax) :
+ CommandObject (name, help, syntax)
+ {
+ }
+
+ virtual
+ ~CommandObjectImageDumpSourceFileList ()
+ {
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ 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 (CommandCompletions::eSourceFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ interpreter,
+ NULL,
+ matches);
+ return matches.GetSize();
+ }
+};
+
+
+class CommandObjectImageDumpSymtab : public CommandObjectImageDumpModuleList
+{
+public:
+ CommandObjectImageDumpSymtab () :
+ CommandObjectImageDumpModuleList ("image dump symtab",
+ "Dump the symbol table from one or more executable images.",
+ "image dump symtab [<file1> ...]")
+ {
+ }
+
+ virtual
+ ~CommandObjectImageDumpSymtab ()
+ {
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, set executable file using 'file' 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 uint32_t num_modules = target->GetImages().GetSize();
+ if (num_modules > 0)
+ {
+ result.GetOutputStream().Printf("Dumping symbol table for %u modules.\n", num_modules);
+ for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ num_dumped++;
+ DumpModuleSymtab (context, 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)
+ {
+ FileSpec image_file(arg_cstr);
+ ModuleList matching_modules;
+ const size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules);
+
+ if (num_matching_modules > 0)
+ {
+ for (size_t i=0; i<num_matching_modules; ++i)
+ {
+ Module *image_module = matching_modules.GetModulePointerAtIndex(i);
+ if (image_module)
+ {
+ num_dumped++;
+ DumpModuleSymtab (context, result.GetOutputStream(), image_module);
+ }
+ }
+ }
+ 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();
+ }
+
+};
+
+//----------------------------------------------------------------------
+// Image section dumping command
+//----------------------------------------------------------------------
+class CommandObjectImageDumpSections : public CommandObjectImageDumpModuleList
+{
+public:
+ CommandObjectImageDumpSections () :
+ CommandObjectImageDumpModuleList (
+ "image dump sections",
+ "Dump the sections from one or more executable images.",
+ "image dump sections [<file1> ...]")
+ {
+ }
+
+ virtual
+ ~CommandObjectImageDumpSections ()
+ {
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, set executable file using 'file' 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 uint32_t num_modules = target->GetImages().GetSize();
+ if (num_modules > 0)
+ {
+ result.GetOutputStream().Printf("Dumping sections for %u modules.\n", num_modules);
+ for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ num_dumped++;
+ DumpModuleSections (context, 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)
+ {
+ FileSpec image_file(arg_cstr);
+ ModuleList matching_modules;
+ const size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules);
+
+ if (num_matching_modules > 0)
+ {
+ for (size_t i=0; i<num_matching_modules; ++i)
+ {
+ Module * image_module = matching_modules.GetModulePointerAtIndex(i);
+ if (image_module)
+ {
+ num_dumped++;
+ DumpModuleSections (context, result.GetOutputStream(), image_module);
+ }
+ }
+ }
+ 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();
+ }
+};
+
+//----------------------------------------------------------------------
+// Image debug symbol dumping command
+//----------------------------------------------------------------------
+class CommandObjectImageDumpSymfile : public CommandObjectImageDumpModuleList
+{
+public:
+ CommandObjectImageDumpSymfile () :
+ CommandObjectImageDumpModuleList ("image dump symfile",
+ "Dump the debug symbol file for one or more executable images.",
+ "image dump symfile [<file1> ...]")
+ {
+ }
+
+ virtual
+ ~CommandObjectImageDumpSymfile ()
+ {
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, set executable file using 'file' 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 uint32_t num_modules = target->GetImages().GetSize();
+ if (num_modules > 0)
+ {
+ result.GetOutputStream().Printf("Dumping debug symbols for %u modules.\n", num_modules);
+ for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ if (DumpModuleSymbolVendor (result.GetOutputStream(), target->GetImages().GetModulePointerAtIndex(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)
+ {
+ FileSpec image_file(arg_cstr);
+ ModuleList matching_modules;
+ const size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules);
+
+ if (num_matching_modules > 0)
+ {
+ for (size_t i=0; i<num_matching_modules; ++i)
+ {
+ Module * image_module = matching_modules.GetModulePointerAtIndex(i);
+ if (image_module)
+ {
+ if (DumpModuleSymbolVendor (result.GetOutputStream(), image_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();
+ }
+};
+
+//----------------------------------------------------------------------
+// Image debug symbol dumping command
+//----------------------------------------------------------------------
+class CommandObjectImageDumpLineTable : public CommandObjectImageDumpSourceFileList
+{
+public:
+ CommandObjectImageDumpLineTable () :
+ CommandObjectImageDumpSourceFileList ("image dump line-table",
+ "Dump the debug symbol file for one or more executable images.",
+ "image dump line-table <file1> [<file2> ...]")
+ {
+ }
+
+ virtual
+ ~CommandObjectImageDumpLineTable ()
+ {
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, set executable file using 'file' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ ExecutionContext exe_ctx(context->GetExecutionContext());
+ 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);
+ const uint32_t num_modules = target->GetImages().GetSize();
+ if (num_modules > 0)
+ {
+ uint32_t num_dumped = 0;
+ for (uint32_t i = 0; i<num_modules; ++i)
+ {
+ if (DumpCompileUnitLineTable (context,
+ result.GetOutputStream(),
+ target->GetImages().GetModulePointerAtIndex(i),
+ file_spec,
+ exe_ctx.process != NULL && exe_ctx.process->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();
+ }
+};
+
+//----------------------------------------------------------------------
+// Dump multi-word command
+//----------------------------------------------------------------------
+class CommandObjectImageDump : public CommandObjectMultiword
+{
+public:
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectImageDump(CommandInterpreter *interpreter) :
+ CommandObjectMultiword ("image dump",
+ "Dumps information in one or more executable images; 'line-table' expects a source file name",
+ "image dump [symtab|sections|symfile|line-table] [<file1> <file2> ...]")
+ {
+ LoadSubCommand (CommandObjectSP (new CommandObjectImageDumpSymtab ()), "symtab", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectImageDumpSections ()), "sections", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectImageDumpSymfile ()), "symfile", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectImageDumpLineTable ()), "line-table", interpreter);
+ }
+
+ virtual
+ ~CommandObjectImageDump()
+ {
+ }
+};
+
+//----------------------------------------------------------------------
+// List images with associated information
+//----------------------------------------------------------------------
+class CommandObjectImageList : public CommandObject
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions () :
+ Options(),
+ m_format_array()
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg)
+ {
+ char short_option = (char) m_getopt_table[option_idx].val;
+ uint32_t width = 0;
+ if (option_arg)
+ width = strtoul (option_arg, NULL, 0);
+ m_format_array.push_back(std::make_pair(short_option, width));
+ Error error;
+ return error;
+ }
+
+ void
+ ResetOptionValues ()
+ {
+ Options::ResetOptionValues();
+ m_format_array.clear();
+ }
+
+ const lldb::OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::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;
+ };
+
+ CommandObjectImageList () :
+ CommandObject (
+ "image list",
+ "List current executable and dependent shared library images.",
+ "image list [<cmd-options>]")
+ {
+ }
+
+ virtual
+ ~CommandObjectImageList ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, set executable file using 'file' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ 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
+ const uint32_t num_modules = target->GetImages().GetSize();
+ if (num_modules > 0)
+ {
+ Stream &strm = result.GetOutputStream();
+
+ for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ Module *module = target->GetImages().GetModulePointerAtIndex(image_idx);
+ strm.Printf("[%3u] ", image_idx);
+
+ if (m_options.m_format_array.empty())
+ {
+ DumpFullpath(strm, &module->GetFileSpec(), 0);
+ }
+ else
+ {
+ const size_t num_entries = m_options.m_format_array.size();
+ for (size_t i=0; i<num_entries; ++i)
+ {
+ if (i > 0)
+ strm.PutChar(' ');
+ 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, width);
+ break;
+
+ case 'f':
+ DumpFullpath (strm, &module->GetFileSpec(), width);
+ break;
+
+ case 'd':
+ DumpDirectory (strm, &module->GetFileSpec(), width);
+ break;
+
+ case 'b':
+ DumpBasename (strm, &module->GetFileSpec(), width);
+ 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')
+ DumpBasename(strm, &symbol_file->GetObjectFile()->GetFileSpec(), width);
+ else
+ DumpFullpath (strm, &symbol_file->GetObjectFile()->GetFileSpec(), width);
+ break;
+ }
+ }
+ strm.Printf("%.*s", width, "<NONE>");
+ }
+ break;
+
+ case 'u':
+ DumpModuleUUID(strm, module);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ strm.EOL();
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("the target has no associated executable images");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ return result.Succeeded();
+ }
+protected:
+
+ CommandOptions m_options;
+};
+
+lldb::OptionDefinition
+CommandObjectImageList::CommandOptions::g_option_table[] =
+{
+{ 0, false, "arch", 'a', optional_argument, NULL, 0, "<width>", "Display the architecture when listing images."},
+{ 0, false, "uuid", 'u', no_argument, NULL, 0, NULL, "Display the UUID when listing images."},
+{ 0, false, "fullpath", 'f', optional_argument, NULL, 0, "<width>", "Display the fullpath to the image object file."},
+{ 0, false, "directory", 'd', optional_argument, NULL, 0, "<width>", "Display the directory with optional width for the image object file."},
+{ 0, false, "basename", 'b', optional_argument, NULL, 0, "<width>", "Display the basename with optional width for the image object file."},
+{ 0, false, "symfile", 's', optional_argument, NULL, 0, "<width>", "Display the fullpath to the image symbol file with optional width."},
+{ 0, false, "symfile-basename", 'S', optional_argument, NULL, 0, "<width>", "Display the basename to the image symbol file with optional width."},
+{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+
+//----------------------------------------------------------------------
+// Lookup information in images
+//----------------------------------------------------------------------
+class CommandObjectImageLookup : public CommandObject
+{
+public:
+
+ enum
+ {
+ eLookupTypeInvalid = -1,
+ eLookupTypeAddress = 0,
+ eLookupTypeSymbol,
+ eLookupTypeFileLine, // Line is optional
+ eLookupTypeFunction,
+ kNumLookupTypes
+ };
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions () :
+ Options()
+ {
+ ResetOptionValues();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg)
+ {
+ Error error;
+
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_type = eLookupTypeAddress;
+ m_addr = Args::StringToUInt64(option_arg, LLDB_INVALID_ADDRESS);
+ if (m_addr == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat ("Invalid address string '%s'.\n", option_arg);
+ break;
+
+ case 'o':
+ m_offset = Args::StringToUInt64(option_arg, LLDB_INVALID_ADDRESS);
+ if (m_offset == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat ("Invalid offset string '%s'.\n", option_arg);
+ break;
+
+ case 's':
+ m_str = option_arg;
+ m_type = eLookupTypeSymbol;
+ break;
+
+ case 'f':
+ m_file.SetFile (option_arg);
+ m_type = eLookupTypeFileLine;
+ break;
+
+ case 'i':
+ m_check_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'.\n", option_arg);
+ else if (m_line_number == 0)
+ error.SetErrorString ("Zero is an invalid line number.");
+ m_type = eLookupTypeFileLine;
+ break;
+
+ case 'n':
+ m_str = option_arg;
+ m_type = eLookupTypeFunction;
+ break;
+
+ case 'r':
+ m_use_regex = true;
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ ResetOptionValues ()
+ {
+ Options::ResetOptionValues();
+ 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_check_inlines = true;
+ }
+
+ const lldb::OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::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_check_inlines;// Check for inline entries when looking up by file/line.
+ };
+
+ CommandObjectImageLookup () :
+ CommandObject (
+ "image lookup",
+ "Look up information within executable and dependent shared library images.",
+ "image lookup [<cmd-options>] [<file1>...]")
+ {
+ }
+
+ virtual
+ ~CommandObjectImageLookup ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+
+ bool
+ LookupInModule (CommandContext *context, Module *module, CommandReturnObject &result, bool &syntax_error)
+ {
+ switch (m_options.m_type)
+ {
+ case eLookupTypeAddress:
+ if (m_options.m_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (LookupAddressInModule (context, result.GetOutputStream(), module, eSymbolContextEverything, m_options.m_addr, m_options.m_offset))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+ case eLookupTypeSymbol:
+ if (!m_options.m_str.empty())
+ {
+ if (LookupSymbolInModule (context, result.GetOutputStream(), module, m_options.m_str.c_str(), m_options.m_use_regex))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+ case eLookupTypeFileLine:
+ if (m_options.m_file)
+ {
+
+ if (LookupFileAndLineInModule (context,
+ result.GetOutputStream(),
+ module,
+ m_options.m_file,
+ m_options.m_line_number,
+ m_options.m_check_inlines))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+ case eLookupTypeFunction:
+ if (!m_options.m_str.empty())
+ {
+ if (LookupFunctionInModule (context,
+ 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;
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, set executable file using 'file' 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)
+ {
+ // Dump all sections for all modules images
+ const uint32_t num_modules = target->GetImages().GetSize();
+ if (num_modules > 0)
+ {
+ for (i = 0; i<num_modules && syntax_error == false; ++i)
+ {
+ if (LookupInModule (context, target->GetImages().GetModulePointerAtIndex(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)
+ {
+ FileSpec image_file(arg_cstr);
+ ModuleList matching_modules;
+ const size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules);
+
+ if (num_matching_modules > 0)
+ {
+ for (size_t i=0; i<num_matching_modules; ++i)
+ {
+ Module * image_module = matching_modules.GetModulePointerAtIndex(i);
+ if (image_module)
+ {
+ if (LookupInModule (context, image_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();
+ }
+protected:
+
+ CommandOptions m_options;
+};
+
+lldb::OptionDefinition
+CommandObjectImageLookup::CommandOptions::g_option_table[] =
+{
+{ 1, true, "address", 'a', required_argument, NULL, 0, "<addr>", "Lookup an address in one or more executable images."},
+{ 1, false, "offset", 'o', required_argument, NULL, 0, "<offset>", "When looking up an address subtract <offset> from any addresses before doing the lookup."},
+{ 2, true, "symbol", 's', required_argument, NULL, 0, "<name>", "Lookup a symbol by name in the symbol tables in one or more executable images."},
+{ 2, false, "regex", 'r', no_argument, NULL, 0, NULL, "The <name> argument for name lookups are regular expressions."},
+{ 3, true, "file", 'f', required_argument, NULL, 0, "<file>", "Lookup a file by fullpath or basename in one or more executable images."},
+{ 3, false, "line", 'l', required_argument, NULL, 0, "<line>", "Lookup a line number in a file (must be used in conjunction with --file)."},
+{ 3, false, "no-inlines", 'i', no_argument, NULL, 0, NULL, "Check inline line entries (must be used in conjunction with --file)."},
+{ 4, true, "function", 'n', required_argument, NULL, 0, "<name>", "Lookup a function by name in the debug symbols in one or more executable images."},
+{ 5, false, "regex", 'r', no_argument, NULL, 0, NULL, "The <name> argument for name lookups are regular expressions."},
+{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+
+
+
+//----------------------------------------------------------------------
+// CommandObjectImage constructor
+//----------------------------------------------------------------------
+CommandObjectImage::CommandObjectImage(CommandInterpreter *interpreter) :
+ CommandObjectMultiword ("image",
+ "Access information for one or more executable images.",
+ "image [dump|list] ...")
+{
+ LoadSubCommand (CommandObjectSP (new CommandObjectImageDump (interpreter)), "dump", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectImageList ()), "list", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectImageLookup ()), "lookup", interpreter);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommandObjectImage::~CommandObjectImage()
+{
+}
+
diff --git a/lldb/source/Commands/CommandObjectImage.h b/lldb/source/Commands/CommandObjectImage.h
new file mode 100644
index 00000000000..8863a3649a3
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectImage.h
@@ -0,0 +1,44 @@
+//===-- CommandObjectImage.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectImage_h_
+#define liblldb_CommandObjectImage_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectImage
+//-------------------------------------------------------------------------
+
+class CommandObjectImage : public CommandObjectMultiword
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectImage(CommandInterpreter *interpreter);
+ virtual
+ ~CommandObjectImage();
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectImage only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectImage);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectImage_h_
diff --git a/lldb/source/Commands/CommandObjectInfo.cpp b/lldb/source/Commands/CommandObjectInfo.cpp
new file mode 100644
index 00000000000..f817cc189b4
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectInfo.cpp
@@ -0,0 +1,32 @@
+//===-- CommandObjectInfo.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectInfo.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectInfo
+//-------------------------------------------------------------------------
+
+CommandObjectInfo::CommandObjectInfo () :
+CommandObjectCrossref ("info", "Lists the kinds of objects for which you can get information, and shows the syntax for doing so.", "info")
+{
+}
+
+CommandObjectInfo::~CommandObjectInfo ()
+{
+}
+
+
diff --git a/lldb/source/Commands/CommandObjectInfo.h b/lldb/source/Commands/CommandObjectInfo.h
new file mode 100644
index 00000000000..44f9bd1a394
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectInfo.h
@@ -0,0 +1,37 @@
+//===-- CommandObjectInfo.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectInfo_h_
+#define liblldb_CommandObjectInfo_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectCrossref.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectInfo
+//-------------------------------------------------------------------------
+
+class CommandObjectInfo : public CommandObjectCrossref
+{
+public:
+ CommandObjectInfo ();
+
+ virtual
+ ~CommandObjectInfo ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectInfo_h_
diff --git a/lldb/source/Commands/CommandObjectLog.cpp b/lldb/source/Commands/CommandObjectLog.cpp
new file mode 100644
index 00000000000..6b54badd7fc
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectLog.cpp
@@ -0,0 +1,452 @@
+//===-- 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 "CommandObjectLog.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/Timer.h"
+
+#include "lldb/Interpreter/CommandContext.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;
+
+
+static LogChannelSP
+GetLogChannelPluginForChannel (const char *channel)
+{
+ std::string log_channel_plugin_name(channel);
+ log_channel_plugin_name += LogChannel::GetPluginSuffix();
+ LogChannelSP log_channel_sp (LogChannel::FindPlugin (log_channel_plugin_name.c_str()));
+ return log_channel_sp;
+}
+
+
+class CommandObjectLogEnable : public CommandObject
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLogEnable() :
+ CommandObject ("log enable",
+ "Enable logging for a single log channel.",
+ "log enable [<cmd-options>] <channel>")
+ {
+ }
+
+ virtual
+ ~CommandObjectLogEnable()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ virtual bool
+ Execute (Args& args,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ if (args.GetArgumentCount() < 1)
+ {
+ result.GetErrorStream() << m_cmd_syntax.c_str();
+ }
+ else
+ {
+ Log::Callbacks log_callbacks;
+
+ std::string channel(args.GetArgumentAtIndex(0));
+ args.Shift (); // Shift off the channel
+ StreamSP log_stream_sp;
+
+ if (m_options.log_file.empty())
+ {
+ std::string log_file("<lldb.debugger>");
+ LogStreamMap::iterator pos = m_log_streams.find(log_file);
+ if (pos == m_log_streams.end())
+ {
+ log_stream_sp = Log::GetStreamForSTDOUT ();
+ if (log_stream_sp)
+ m_log_streams[log_file] = log_stream_sp;
+ }
+ else
+ log_stream_sp = pos->second;
+ }
+ else
+ {
+ LogStreamMap::iterator pos = m_log_streams.find(m_options.log_file);
+ if (pos == m_log_streams.end())
+ {
+ log_stream_sp.reset (new StreamFile (m_options.log_file.c_str(), "w"));
+ m_log_streams[m_options.log_file] = log_stream_sp;
+ }
+ else
+ log_stream_sp = pos->second;
+ }
+ assert (log_stream_sp.get());
+ uint32_t log_options = m_options.log_options;
+ if (log_options == 0)
+ log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE;
+ if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
+ {
+ log_callbacks.enable (log_stream_sp, log_options, args, &result.GetErrorStream());
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
+ if (log_channel_sp)
+ {
+ if (log_channel_sp->Enable (log_stream_sp, log_options, &result.GetErrorStream(), args))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions () :
+ Options (),
+ log_file (),
+ log_options (0)
+ {
+ }
+
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg)
+ {
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'f': log_file = option_arg; 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;
+ default:
+ error.SetErrorStringWithFormat ("Unrecognized option '%c'\n", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ ResetOptionValues ()
+ {
+ Options::ResetOptionValues();
+ log_file.clear();
+ log_options = 0;
+ }
+
+ const lldb::OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string log_file;
+ uint32_t log_options;
+ };
+
+protected:
+ typedef std::map<std::string, StreamSP> LogStreamMap;
+ CommandOptions m_options;
+ LogStreamMap m_log_streams;
+};
+
+lldb::OptionDefinition
+CommandObjectLogEnable::CommandOptions::g_option_table[] =
+{
+{ 0, false, "file", 'f', required_argument, NULL, 0, "<filename>", "Set the destination file to log to."},
+{ 0, false, "threadsafe", 't', no_argument, NULL, 0, NULL, "Enable thread safe logging to avoid interweaved log lines." },
+{ 0, false, "verbose", 'v', no_argument, NULL, 0, NULL, "Enable verbose logging." },
+{ 0, false, "debug", 'g', no_argument, NULL, 0, NULL, "Enable debug logging." },
+{ 0, false, "sequence", 's', no_argument, NULL, 0, NULL, "Prepend all log lines with an increasing integer sequence id." },
+{ 0, false, "timestamp", 'T', no_argument, NULL, 0, NULL, "Prepend all log lines with a timestamp." },
+{ 0, false, "pid-tid", 'p', no_argument, NULL, 0, NULL, "Prepend all log lines with the process and thread ID that generates the log line." },
+{ 0, false, "thread-name",'n', no_argument, NULL, 0, NULL, "Prepend all log lines with the thread name for the thread that generates the log line." },
+{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+class CommandObjectLogDisable : public CommandObject
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLogDisable() :
+ CommandObject ("log disable",
+ "Disable one or more log channels.",
+ "log disable <channel> [<channel> ...]")
+ {
+ }
+
+ virtual
+ ~CommandObjectLogDisable()
+ {
+ }
+
+ virtual bool
+ Execute (Args& args,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ const size_t argc = args.GetArgumentCount();
+ if (argc == 0)
+ {
+ result.GetErrorStream() << m_cmd_syntax.c_str();
+ }
+ else
+ {
+ for (size_t i=0; i<argc; ++i)
+ {
+ Log::Callbacks log_callbacks;
+
+ std::string channel(args.GetArgumentAtIndex(i));
+ if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
+ {
+ log_callbacks.disable ();
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else if (channel == "all")
+ {
+ Log::DisableAllLogChannels();
+ }
+ else
+ {
+ LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
+ if (log_channel_sp)
+ {
+ log_channel_sp->Disable();
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+class CommandObjectLogList : public CommandObject
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLogList() :
+ CommandObject ("log list",
+ "List the log categories for one or more log channels.",
+ "log list <channel> [<channel> ...]")
+ {
+ }
+
+ virtual
+ ~CommandObjectLogList()
+ {
+ }
+
+ virtual bool
+ Execute (Args& args,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ 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 (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 (GetLogChannelPluginForChannel(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 CommandObject
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLogTimer() :
+ CommandObject ("log timers",
+ "Enable, disable, dump, and reset LLDB internal performance timers.",
+ "log timers < enable | disable | dump | reset >")
+ {
+ }
+
+ virtual
+ ~CommandObjectLogTimer()
+ {
+ }
+
+ virtual bool
+ Execute (Args& args,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ 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);
+ }
+
+ }
+ 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 ("log",
+ "A set of commands for operating on logs.",
+ "log <command> [<command-options>]")
+{
+ LoadSubCommand (CommandObjectSP (new CommandObjectLogEnable), "enable", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectLogDisable), "disable", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectLogList), "list", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectLogTimer), "timers", interpreter);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommandObjectLog::~CommandObjectLog()
+{
+}
+
+
+
+
diff --git a/lldb/source/Commands/CommandObjectLog.h b/lldb/source/Commands/CommandObjectLog.h
new file mode 100644
index 00000000000..a1ba258ea33
--- /dev/null
+++ b/lldb/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/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp
new file mode 100644
index 00000000000..91abd81e9fd
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectMemory.cpp
@@ -0,0 +1,680 @@
+//===-- 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 "CommandObjectMemory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandContext.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Read memory from the inferior process
+//----------------------------------------------------------------------
+class CommandObjectMemoryRead : public CommandObject
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+ CommandOptions () :
+ Options()
+ {
+ ResetOptionValues();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg)
+ {
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'f':
+ error = Args::StringToFormat (option_arg, m_format);
+
+ switch (m_format)
+ {
+ default:
+ break;
+
+ case eFormatBoolean:
+ if (m_byte_size == 0)
+ m_byte_size = 1;
+ if (m_num_per_line == 0)
+ m_num_per_line = 1;
+ break;
+
+ case eFormatCString:
+ if (m_num_per_line == 0)
+ m_num_per_line = 1;
+ break;
+
+ case eFormatPointer:
+ break;
+
+ case eFormatBinary:
+ case eFormatFloat:
+ case eFormatOctal:
+ case eFormatDecimal:
+ case eFormatEnum:
+ case eFormatUnicode16:
+ case eFormatUnicode32:
+ case eFormatUnsigned:
+ if (m_byte_size == 0)
+ m_byte_size = 4;
+ if (m_num_per_line == 0)
+ m_num_per_line = 1;
+ break;
+
+ case eFormatBytes:
+ case eFormatBytesWithASCII:
+ case eFormatChar:
+ case eFormatCharPrintable:
+ if (m_byte_size == 0)
+ m_byte_size = 1;
+ break;
+ case eFormatComplex:
+ if (m_byte_size == 0)
+ m_byte_size = 8;
+ break;
+ case eFormatHex:
+ if (m_byte_size == 0)
+ m_byte_size = 4;
+ 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:
+ break;
+ }
+ break;
+
+ case 'l':
+ m_num_per_line = Args::StringToUInt32 (option_arg, 0);
+ if (m_num_per_line == 0)
+ error.SetErrorStringWithFormat("Invalid value for --num-per-line option '%s'. Must be positive integer value.\n", option_arg);
+ break;
+
+ case 'c':
+ m_count = Args::StringToUInt32 (option_arg, 0);
+ if (m_count == 0)
+ error.SetErrorStringWithFormat("Invalid value for --count option '%s'. Must be positive integer value.\n", option_arg);
+ break;
+
+ case 's':
+ m_byte_size = Args::StringToUInt32 (option_arg, 0);
+ if (m_byte_size == 0)
+ error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ ResetOptionValues ()
+ {
+ Options::ResetOptionValues();
+ m_format = eFormatBytesWithASCII;
+ m_byte_size = 0;
+ m_count = 0;
+ m_num_per_line = 0;
+ }
+
+ const lldb::OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ lldb::Format m_format;
+ uint32_t m_byte_size;
+ uint32_t m_count;
+ uint32_t m_num_per_line;
+ };
+
+ CommandObjectMemoryRead () :
+ CommandObject ("memory read",
+ "Read memory from the process being debugged.",
+ "memory read [<cmd-options>] <start-addr> [<end-addr>]",
+ eFlagProcessMustBeLaunched)
+ {
+ }
+
+ virtual
+ ~CommandObjectMemoryRead ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Process *process = context->GetExecutionContext().process;
+ if (process == NULL)
+ {
+ result.AppendError("need a process to read memory");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc == 0 || argc > 2)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 or two args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ size_t item_byte_size = m_options.m_byte_size;
+ if (item_byte_size == 0)
+ {
+ if (m_options.m_format == eFormatPointer)
+ item_byte_size = process->GetAddressByteSize();
+ else
+ item_byte_size = 1;
+ }
+
+ size_t item_count = m_options.m_count;
+
+ size_t num_per_line = m_options.m_num_per_line;
+ if (num_per_line == 0)
+ {
+ num_per_line = (16/item_byte_size);
+ if (num_per_line == 0)
+ num_per_line = 1;
+ }
+
+ size_t total_byte_size = m_options.m_count * item_byte_size;
+ if (total_byte_size == 0)
+ total_byte_size = 32;
+
+ lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ result.AppendErrorWithFormat("invalid start address string '%s'.\n", command.GetArgumentAtIndex(0));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (argc == 2)
+ {
+ lldb::addr_t end_addr = Args::StringToUInt64(command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
+ if (end_addr == LLDB_INVALID_ADDRESS)
+ {
+ result.AppendErrorWithFormat("Invalid end address string '%s'.\n", command.GetArgumentAtIndex(1));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (end_addr <= addr)
+ {
+ result.AppendErrorWithFormat("End address (0x%llx) must be greater that the start address (0x%llx).\n", end_addr, addr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (item_count != 0)
+ {
+ result.AppendErrorWithFormat("Specify either the end address (0x%llx) or the count (--count %u), 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;
+ }
+ else
+ {
+ if (item_count == 0)
+ item_count = 32;
+ }
+
+ DataBufferSP data_sp(new DataBufferHeap (total_byte_size, '\0'));
+ Error error;
+ size_t bytes_read = process->ReadMemory(addr, data_sp->GetBytes (), data_sp->GetByteSize(), error);
+ if (bytes_read == 0)
+ {
+ result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr);
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (bytes_read < total_byte_size)
+ result.AppendWarningWithFormat("Not all bytes (%u/%u) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr);
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ DataExtractor data(data_sp, process->GetByteOrder(), process->GetAddressByteSize());
+
+ Stream &output_stream = result.GetOutputStream();
+ data.Dump(&output_stream,
+ 0,
+ m_options.m_format,
+ item_byte_size,
+ item_count,
+ num_per_line,
+ addr,
+ 0,
+ 0);
+ output_stream.EOL();
+ return true;
+ }
+
+protected:
+ CommandOptions m_options;
+};
+
+lldb::OptionDefinition
+CommandObjectMemoryRead::CommandOptions::g_option_table[] =
+{
+ { 0, false, "format", 'f', required_argument, NULL, 0, "<format>", "The format that will be used to display the memory. Defaults to bytes with ASCII (--format=Y)."},
+ { 0, false, "size", 's', required_argument, NULL, 0, "<byte-size>","The size in bytes to use when displaying with the selected format."},
+ { 0, false, "num-per-line", 'l', required_argument, NULL, 0, "<N>", "The number of items per line to display."},
+ { 0, false, "count", 'c', required_argument, NULL, 0, "<N>", "The number of total items to display."},
+ { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+//----------------------------------------------------------------------
+// Write memory to the inferior process
+//----------------------------------------------------------------------
+class CommandObjectMemoryWrite : public CommandObject
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+ CommandOptions () :
+ Options()
+ {
+ ResetOptionValues();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg)
+ {
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+ switch (short_option)
+ {
+ case 'f':
+ error = Args::StringToFormat (option_arg, m_format);
+ break;
+
+ case 's':
+ m_byte_size = Args::StringToUInt32 (option_arg, 0);
+ if (m_byte_size == 0)
+ error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg);
+ break;
+
+
+ default:
+ error.SetErrorStringWithFormat("Unrecognized short option '%c'\n", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ ResetOptionValues ()
+ {
+ Options::ResetOptionValues();
+ m_format = eFormatBytes;
+ m_byte_size = 1;
+ }
+
+ const lldb::OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ lldb::Format m_format;
+ uint32_t m_byte_size;
+ };
+
+ CommandObjectMemoryWrite () :
+ CommandObject ("memory write",
+ "Write memory to the process being debugged.",
+ "memory write [<cmd-options>] <addr> [value1 value2 ...]",
+ eFlagProcessMustBeLaunched)
+ {
+ }
+
+ virtual
+ ~CommandObjectMemoryWrite ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ 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;
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Process *process = context->GetExecutionContext().process;
+ if (process == NULL)
+ {
+ result.AppendError("need a process to read memory");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 2)
+ {
+ result.AppendErrorWithFormat ("%s takes an address and at least one value.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ size_t item_byte_size = m_options.m_byte_size ? m_options.m_byte_size : 1;
+ StreamString buffer (Stream::eBinary,
+ process->GetAddressByteSize(),
+ process->GetByteOrder());
+
+ lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ command.Shift(); // shift off the address argument
+ uint64_t uval64;
+ int64_t sval64;
+ bool success = false;
+ const uint32_t num_value_args = command.GetArgumentCount();
+ uint32_t i;
+ for (i=0; i<num_value_args; ++i)
+ {
+ const char *value_str = command.GetArgumentAtIndex(i);
+
+ switch (m_options.m_format)
+ {
+ 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:
+ result.AppendError("unsupported format for writing memory");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+
+ case eFormatDefault:
+ case eFormatBytes:
+ case eFormatHex:
+ // 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%llx is too large to fit in a %u 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%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (uval64, item_byte_size);
+ break;
+
+ case eFormatChar:
+ case eFormatCString:
+ if (value_str[0])
+ {
+ size_t len = strlen (value_str);
+ // Include the NULL for C strings...
+ if (m_options.m_format == eFormatCString)
+ ++len;
+ Error error;
+ if (process->WriteMemory (addr, value_str, len, error) == len)
+ {
+ addr += len;
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Memory write to 0x%llx 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 %lli is too large or small to fit in a %u 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 %llu is too large to fit in a %u 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 %llo is too large to fit in a %u 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().data(), buffer.GetString().size(), error) == buffer.GetString().size())
+ return true;
+ else
+ {
+ result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ return true;
+ }
+
+protected:
+ CommandOptions m_options;
+};
+
+lldb::OptionDefinition
+CommandObjectMemoryWrite::CommandOptions::g_option_table[] =
+{
+ { 0, false, "format", 'f', required_argument, NULL, 0, "<format>", "The format value types that will be decoded and written to memory."},
+ { 0, false, "size", 's', required_argument, NULL, 0, "<byte-size>","The size in bytes of the values to write to memory."},
+ { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectMemory
+//-------------------------------------------------------------------------
+
+CommandObjectMemory::CommandObjectMemory (CommandInterpreter *interpreter) :
+ CommandObjectMultiword ("memory",
+ "A set of commands for operating on a memory.",
+ "memory <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand (CommandObjectSP (new CommandObjectMemoryRead ()), "read", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectMemoryWrite ()), "write", interpreter);
+}
+
+CommandObjectMemory::~CommandObjectMemory ()
+{
+}
diff --git a/lldb/source/Commands/CommandObjectMemory.h b/lldb/source/Commands/CommandObjectMemory.h
new file mode 100644
index 00000000000..a4665401510
--- /dev/null
+++ b/lldb/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/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
new file mode 100644
index 00000000000..ea0f6aff5eb
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -0,0 +1,833 @@
+//===-- 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 "CommandObjectProcess.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Core/State.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessLaunch
+//-------------------------------------------------------------------------
+
+class CommandObjectProcessLaunch : public CommandObject
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions () :
+ Options()
+ {
+ // Keep default values of all options in one place: ResetOptionValues ()
+ ResetOptionValues ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (int option_idx, const char *option_arg)
+ {
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 's': stop_at_entry = true; break;
+ case 'e': stderr_path = option_arg; break;
+ case 'i': stdin_path = option_arg; break;
+ case 'o': stdout_path = option_arg; break;
+ case 'p': plugin_name = option_arg; break;
+ default:
+ error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ ResetOptionValues ()
+ {
+ Options::ResetOptionValues();
+ stop_at_entry = false;
+ stdin_path.clear();
+ stdout_path.clear();
+ stderr_path.clear();
+ plugin_name.clear();
+ }
+
+ const lldb::OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool stop_at_entry;
+ std::string stderr_path;
+ std::string stdin_path;
+ std::string stdout_path;
+ std::string plugin_name;
+
+ };
+
+ CommandObjectProcessLaunch () :
+ CommandObject ("process launch",
+ "Launches the executable in the debugger.",
+ "process launch [<cmd-options>] [<arguments-for-running-the-program>]")
+ {
+ }
+
+
+ ~CommandObjectProcessLaunch ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ bool
+ Execute (Args& launch_args,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target *target = context->GetTarget();
+ bool synchronous_execution = interpreter->GetSynchronous ();
+ // bool launched = false;
+ // bool stopped_after_launch = false;
+
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, set executable file using 'file' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // If our listener is NULL, users aren't allows to launch
+ Listener *listener = interpreter->GetListener();
+ if (listener == NULL)
+ {
+ result.AppendError ("operation not allowed through the command interpreter");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ char filename[PATH_MAX];
+ Module *exe_module = target->GetExecutableModule().get();
+ exe_module->GetFileSpec().GetPath(filename, sizeof(filename));
+
+ Process *process = context->GetExecutionContext().process;
+ if (process)
+ {
+ if (process->IsAlive())
+ {
+ result.AppendErrorWithFormat ("Process %u is currently being debugged, kill the process before running again.\n",
+ process->GetID());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ const char *plugin_name;
+ if (!m_options.plugin_name.empty())
+ plugin_name = m_options.plugin_name.c_str();
+ else
+ plugin_name = NULL;
+
+ process = target->CreateProcess (*listener, plugin_name).get();
+
+ const Args *environment = interpreter->GetEnvironmentVariables();
+ const Args *run_args = interpreter->GetProgramArguments();
+
+ // There are two possible sources of args to be passed to the process upon launching: Those the user
+ // typed at the run command (launch_args); or those the user pre-set in the run-args variable (run_args).
+
+ // If launch_args is empty, use run_args.
+ if (launch_args.GetArgumentCount() == 0)
+ {
+ if (run_args != NULL)
+ launch_args.AppendArguments (*run_args);
+ }
+ else
+ {
+ // launch-args was not empty; use that, AND re-set run-args to contains launch-args values.
+ StateVariable *run_args_var = interpreter->GetStateVariable ("run-args");
+ if (run_args_var != NULL)
+ {
+ run_args_var->ArrayClearValues();
+ run_args_var->GetArgs().AppendArguments (launch_args);
+ }
+ }
+
+
+ if (process)
+ {
+ const char *archname = exe_module->GetArchitecture().AsCString();
+
+ const char * stdin_path = NULL;
+ const char * stdout_path = NULL;
+ const char * stderr_path = NULL;
+
+ if (!(m_options.stdin_path.empty() &&
+ m_options.stdout_path.empty() &&
+ m_options.stderr_path.empty()))
+ {
+ stdin_path = m_options.stdin_path.empty() ? "/dev/null" : m_options.stdin_path.c_str();
+ stdout_path = m_options.stdout_path.empty() ? "/dev/null" : m_options.stdout_path.c_str();
+ stderr_path = m_options.stderr_path.empty() ? "/dev/null" : m_options.stderr_path.c_str();
+ }
+
+ Error error (process->Launch (launch_args.GetConstArgumentVector(),
+ environment ? environment->GetConstArgumentVector() : NULL,
+ stdin_path,
+ stdout_path,
+ stderr_path));
+
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat ("Launching '%s' (%s)\n", filename, archname);
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ if (m_options.stop_at_entry == false)
+ {
+ StateType state = process->WaitForProcessToStop (NULL);
+
+ if (state == eStateStopped)
+ {
+ // Call continue_command.
+ CommandReturnObject continue_result;
+ interpreter->HandleCommand("process continue", false, continue_result);
+ }
+
+ if (synchronous_execution)
+ {
+ result.SetDidChangeProcessState (true);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Process launch failed: %s",
+ error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Process launch failed: unable to create a process object.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ return result.Succeeded();
+ }
+
+protected:
+
+ CommandOptions m_options;
+};
+
+
+lldb::OptionDefinition
+CommandObjectProcessLaunch::CommandOptions::g_option_table[] =
+{
+{ 0, false, "stop-at-entry", 's', no_argument, NULL, 0, NULL, "Stop at the entry point of the program when launching a process."},
+{ 0, false, "stdin", 'i', required_argument, NULL, 0, "<path>", "Redirect stdin for the process to <path>."},
+{ 0, false, "stdout", 'o', required_argument, NULL, 0, "<path>", "Redirect stdout for the process to <path>."},
+{ 0, false, "stderr", 'e', required_argument, NULL, 0, "<path>", "Redirect stderr for the process to <path>."},
+{ 0, false, "plugin", 'p', required_argument, NULL, 0, "<plugin>", "Name of the process plugin you want to use."},
+{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessAttach
+//-------------------------------------------------------------------------
+
+class CommandObjectProcessAttach : public CommandObject
+{
+public:
+
+ CommandObjectProcessAttach () :
+ CommandObject ("process attach",
+ "Attaches to a process.",
+ "process attach <cmd-options>")
+ {
+ SetHelpLong("Currently, you must set the executable file before you can attach "
+ "to a process.\n");
+ }
+
+ ~CommandObjectProcessAttach ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, set executable file using 'file' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // If our listener is NULL, users aren't allows to launch
+ Listener *listener = interpreter->GetListener();
+ if (listener == NULL)
+ {
+ result.AppendError ("operation not allowed through the command interpreter");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ Process *process = context->GetExecutionContext().process;
+ if (process)
+ {
+ if (process->IsAlive())
+ {
+ result.AppendErrorWithFormat ("Process %u is currently being debugged, kill the process before attaching.\n", process->GetID());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (command.GetArgumentCount())
+ {
+ result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ const char *plugin_name = NULL;
+
+ if (!m_options.plugin_name.empty())
+ plugin_name = m_options.plugin_name.c_str();
+
+ process = target->CreateProcess (*listener, plugin_name).get();
+
+ if (process)
+ {
+ Error error;
+ int attach_pid = m_options.pid;
+
+ if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ error = process->Attach (attach_pid);
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Attaching to process %i failed: %s.\n",
+ attach_pid,
+ error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else if (!m_options.name.empty())
+ {
+ error = process->Attach (m_options.name.c_str(), m_options.waitfor);
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ else
+ {
+ if (m_options.waitfor)
+ result.AppendErrorWithFormat ("Waiting for a process to launch named '%s': %s\n",
+ m_options.name.c_str(),
+ error.AsCString());
+ else
+ result.AppendErrorWithFormat ("Failed to a process named '%s': %s\n",
+ m_options.name.c_str(),
+ error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions () :
+ Options()
+ {
+ // Keep default values of all options in one place: ResetOptionValues ()
+ ResetOptionValues ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (int option_idx, const char *option_arg)
+ {
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+ bool success = false;
+ switch (short_option)
+ {
+ case 'p':
+ pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success);
+ if (!success || pid == LLDB_INVALID_PROCESS_ID)
+ {
+ error.SetErrorStringWithFormat("Invalid process ID '%s'.\n", option_arg);
+ }
+ break;
+
+ case 'P':
+ plugin_name = option_arg;
+ break;
+
+ case 'n':
+ name.assign(option_arg);
+ break;
+
+ case 'w':
+ waitfor = true;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ ResetOptionValues ()
+ {
+ Options::ResetOptionValues();
+ pid = LLDB_INVALID_PROCESS_ID;
+ name.clear();
+ waitfor = false;
+ }
+
+ const lldb::OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ lldb::pid_t pid;
+ std::string plugin_name;
+ std::string name;
+ bool waitfor;
+ };
+
+protected:
+
+ CommandOptions m_options;
+};
+
+
+lldb::OptionDefinition
+CommandObjectProcessAttach::CommandOptions::g_option_table[] =
+{
+{ 0, false, "pid", 'p', required_argument, NULL, 0, "<pid>", "The process ID of an existing process to attach to."},
+{ 0, false, "plugin", 'P', required_argument, NULL, 0, "<plugin>", "Name of the process plugin you want to use."},
+{ 1, true, "name", 'n', required_argument, NULL, 0, "<process-name>", "The name of the process to attach to."},
+{ 1, false, "waitfor", 'w', no_argument, NULL, 0, NULL, "Wait for the the process with <process-name> to launch."},
+{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessContinue
+//-------------------------------------------------------------------------
+
+class CommandObjectProcessContinue : public CommandObject
+{
+public:
+
+ CommandObjectProcessContinue () :
+ CommandObject ("process continue",
+ "Continues execution all threads in the current process.",
+ "process continue",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+ {
+ }
+
+
+ ~CommandObjectProcessContinue ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Process *process = context->GetExecutionContext().process;
+ bool synchronous_execution = interpreter->GetSynchronous ();
+
+ if (process == NULL)
+ {
+ result.AppendError ("no process to continue");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ 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;
+ }
+
+ 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 ("Resuming process %i\n", process->GetID());
+ if (synchronous_execution)
+ {
+ StateType state = process->WaitForProcessToStop (NULL);
+
+ result.SetDidChangeProcessState (true);
+ result.AppendMessageWithFormat ("Process %i %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();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessDetach
+//-------------------------------------------------------------------------
+
+class CommandObjectProcessDetach : public CommandObject
+{
+public:
+
+ CommandObjectProcessDetach () :
+ CommandObject ("process detach",
+ "Detaches from the current process being debugged.",
+ "process detach",
+ eFlagProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectProcessDetach ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Process *process = context->GetExecutionContext().process;
+ if (process == NULL)
+ {
+ result.AppendError ("must have a valid process in order to detach");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Error error (process->Detach());
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Detach failed: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessSignal
+//-------------------------------------------------------------------------
+
+class CommandObjectProcessSignal : public CommandObject
+{
+public:
+
+ CommandObjectProcessSignal () :
+ CommandObject ("process signal",
+ "Sends a UNIX signal to the current process being debugged.",
+ "process signal <unix-signal-number>")
+ {
+ }
+
+ ~CommandObjectProcessSignal ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Process *process = context->GetExecutionContext().process;
+ if (process == NULL)
+ {
+ result.AppendError ("no process to signal");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 1)
+ {
+ int signo = Args::StringToSInt32(command.GetArgumentAtIndex(0), -1, 0);
+ if (signo == -1)
+ {
+ 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: \n", m_cmd_name.c_str(),
+ m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessInterrupt
+//-------------------------------------------------------------------------
+
+class CommandObjectProcessInterrupt : public CommandObject
+{
+public:
+
+
+ CommandObjectProcessInterrupt () :
+ CommandObject ("process interrupt",
+ "Interrupts the current process being debugged.",
+ "process interrupt",
+ eFlagProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectProcessInterrupt ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Process *process = context->GetExecutionContext().process;
+ if (process == NULL)
+ {
+ result.AppendError ("no process to halt");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ Error error(process->Halt ());
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ // Maybe we should add a "SuspendThreadPlans so we
+ // can halt, and keep in place all the current thread plans.
+ process->GetThreadList().DiscardThreadPlans();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to halt process: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: \n",
+ m_cmd_name.c_str(),
+ m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessKill
+//-------------------------------------------------------------------------
+
+class CommandObjectProcessKill : public CommandObject
+{
+public:
+
+ CommandObjectProcessKill () :
+ CommandObject ("process kill",
+ "Terminates the current process being debugged.",
+ "process kill",
+ eFlagProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectProcessKill ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Process *process = context->GetExecutionContext().process;
+ 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: \n",
+ m_cmd_name.c_str(),
+ m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordProcess
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordProcess::CommandObjectMultiwordProcess (CommandInterpreter *interpreter) :
+ CommandObjectMultiword ("process",
+ "A set of commands for operating on a process.",
+ "process <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand (CommandObjectSP (new CommandObjectProcessAttach ()), "attach", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectProcessLaunch ()), "launch", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectProcessContinue ()), "continue", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectProcessDetach ()), "detach", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectProcessSignal ()), "signal", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectProcessInterrupt ()), "interrupt", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectProcessKill ()), "kill", interpreter);
+}
+
+CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess ()
+{
+}
+
diff --git a/lldb/source/Commands/CommandObjectProcess.h b/lldb/source/Commands/CommandObjectProcess.h
new file mode 100644
index 00000000000..9a8d59e70e6
--- /dev/null
+++ b/lldb/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/lldb/source/Commands/CommandObjectQuit.cpp b/lldb/source/Commands/CommandObjectQuit.cpp
new file mode 100644
index 00000000000..b66f4b108ff
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectQuit.cpp
@@ -0,0 +1,48 @@
+//===-- 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 "CommandObjectQuit.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "CommandInterpreter.h"
+#include "CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectQuit
+//-------------------------------------------------------------------------
+
+CommandObjectQuit::CommandObjectQuit () :
+ CommandObject ("quit", "Quits out of the LLDB debugger.", "quit")
+{
+}
+
+CommandObjectQuit::~CommandObjectQuit ()
+{
+}
+
+bool
+CommandObjectQuit::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ interpreter->BroadcastEvent (CommandInterpreter::eBroadcastBitQuitCommandReceived);
+ result.SetStatus (eReturnStatusQuit);
+ return true;
+}
+
diff --git a/lldb/source/Commands/CommandObjectQuit.h b/lldb/source/Commands/CommandObjectQuit.h
new file mode 100644
index 00000000000..a45d8a4b51b
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectQuit.h
@@ -0,0 +1,51 @@
+//===-- 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
+//-------------------------------------------------------------------------
+
+// SPECIAL NOTE!! The CommandObjectQuit is special, because the actual function to execute
+// when the user types 'quit' is passed (via function pointer) to the Command Interpreter when it
+// is constructed. The function pointer is then stored in this CommandObjectQuit, and is invoked
+// via the CommandObjectQuit::Execute function. This is the only command object that works this
+// way; it was done this way because different Command Interpreter callers may want or need different things
+// to be done in order to shut down properly.
+
+class CommandObjectQuit : public CommandObject
+{
+public:
+
+ CommandObjectQuit ();
+
+ virtual
+ ~CommandObjectQuit ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectQuit_h_
diff --git a/lldb/source/Commands/CommandObjectRegister.cpp b/lldb/source/Commands/CommandObjectRegister.cpp
new file mode 100644
index 00000000000..c4cb705c725
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectRegister.cpp
@@ -0,0 +1,231 @@
+//===-- 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 "CommandObjectRegister.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Interpreter/CommandContext.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/RegisterContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// "register read"
+//----------------------------------------------------------------------
+class CommandObjectRegisterRead : public CommandObject
+{
+public:
+ CommandObjectRegisterRead () :
+ CommandObject ("register read",
+ "Dump the one or more register values from the current frame.",
+ "register read [<reg-name1> [<reg-name2> [...]]]",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+ {
+ }
+
+ virtual
+ ~CommandObjectRegisterRead ()
+ {
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ StreamString &output_stream = result.GetOutputStream();
+ DataExtractor reg_data;
+ ExecutionContext exe_ctx(context->GetExecutionContext());
+ RegisterContext *reg_context = exe_ctx.GetRegisterContext ();
+
+ if (reg_context)
+ {
+ const RegisterInfo *reg_info = NULL;
+ if (command.GetArgumentCount() == 0)
+ {
+ uint32_t set_idx;
+ const uint32_t num_register_sets = reg_context->GetRegisterSetCount();
+ for (set_idx = 0; set_idx < num_register_sets; ++set_idx)
+ {
+ uint32_t unavailable_count = 0;
+ const RegisterSet * const reg_set = reg_context->GetRegisterSet(set_idx);
+ output_stream.Printf ("%s:\n", reg_set->name);
+ output_stream.IndentMore ();
+ const uint32_t num_registers = reg_set->num_registers;
+ for (uint32_t reg_idx = 0; reg_idx < num_registers; ++reg_idx)
+ {
+ uint32_t reg = reg_set->registers[reg_idx];
+ reg_info = reg_context->GetRegisterInfoAtIndex(reg);
+ if (reg_context->ReadRegisterBytes(reg, reg_data))
+ {
+ output_stream.Indent ();
+ output_stream.Printf ("%-12s = ", reg_info ? reg_info->name : "<INVALID REGINFO>");
+ reg_data.Dump(&output_stream, 0, reg_info->format, reg_info->byte_size, 1, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
+ output_stream.EOL();
+ }
+ else
+ {
+ ++unavailable_count;
+ }
+ }
+ if (unavailable_count)
+ {
+ output_stream.Indent ();
+ output_stream.Printf("%u registers were unavailable.\n", unavailable_count);
+ }
+ output_stream.IndentLess ();
+ output_stream.EOL();
+ }
+ }
+ else
+ {
+ const char *arg_cstr;
+ for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
+ {
+ reg_info = reg_context->GetRegisterInfoByName(arg_cstr);
+
+ if (reg_info)
+ {
+ output_stream.Printf("%-12s = ", reg_info->name);
+ if (reg_context->ReadRegisterBytes(reg_info->reg, reg_data))
+ {
+ reg_data.Dump(&output_stream, 0, reg_info->format, reg_info->byte_size, 1, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
+ }
+ else
+ {
+ output_stream.PutCString ("error: unavailable");
+ }
+ output_stream.EOL();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid register name '%s'.\n", arg_cstr);
+ }
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("no current frame");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+//----------------------------------------------------------------------
+// "register write"
+//----------------------------------------------------------------------
+class CommandObjectRegisterWrite : public CommandObject
+{
+public:
+ CommandObjectRegisterWrite () :
+ CommandObject ("register write",
+ "Modify a single register value.",
+ "register write <reg-name> <value>",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+ {
+ }
+
+ virtual
+ ~CommandObjectRegisterWrite ()
+ {
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ DataExtractor reg_data;
+ ExecutionContext exe_ctx(context->GetExecutionContext());
+ RegisterContext *reg_context = exe_ctx.GetRegisterContext ();
+
+ if (reg_context)
+ {
+ 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);
+ const RegisterInfo *reg_info = reg_context->GetRegisterInfoByName(reg_name);
+
+ if (reg_info)
+ {
+ Scalar scalar;
+ Error error(scalar.SetValueFromCString (value_str, reg_info->encoding, reg_info->byte_size));
+ if (error.Success())
+ {
+ if (reg_context->WriteRegisterValue(reg_info->reg, scalar))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to write register '%s' with value '%s': %s\n",
+ reg_name,
+ value_str,
+ error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Register not found for '%s'.\n", reg_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("no current frame");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+//----------------------------------------------------------------------
+// CommandObjectRegister constructor
+//----------------------------------------------------------------------
+CommandObjectRegister::CommandObjectRegister(CommandInterpreter *interpreter) :
+ CommandObjectMultiword ("register",
+ "Access thread registers.",
+ "register [read|write] ...")
+{
+ LoadSubCommand (CommandObjectSP (new CommandObjectRegisterRead ()), "read", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectRegisterWrite ()), "write", interpreter);
+}
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommandObjectRegister::~CommandObjectRegister()
+{
+}
diff --git a/lldb/source/Commands/CommandObjectRegister.h b/lldb/source/Commands/CommandObjectRegister.h
new file mode 100644
index 00000000000..740bc5424e4
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectRegister.h
@@ -0,0 +1,44 @@
+//===-- 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/lldb/source/Commands/CommandObjectRemove.cpp b/lldb/source/Commands/CommandObjectRemove.cpp
new file mode 100644
index 00000000000..28736cd16ec
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectRemove.cpp
@@ -0,0 +1,89 @@
+//===-- CommandObjectRemove.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectRemove.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;
+
+//-------------------------------------------------------------------------
+// CommandObjectRemove
+//-------------------------------------------------------------------------
+
+CommandObjectRemove::CommandObjectRemove () :
+ CommandObject ("remove",
+ "Allows the user to remove/delete user-defined command functions (script functions).",
+ "remove <command-name-to-be-removed>")
+{
+}
+
+CommandObjectRemove::~CommandObjectRemove()
+{
+}
+
+
+bool
+CommandObjectRemove::Execute (Args& args, CommandContext *context, CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+{
+ CommandObject::CommandMap::iterator pos;
+ CommandObject *cmd_obj;
+
+ if (args.GetArgumentCount() != 0)
+ {
+ const char *command_name = args.GetArgumentAtIndex(0);
+ cmd_obj = interpreter->GetCommandObject(command_name);
+ if (cmd_obj)
+ {
+ if (interpreter->CommandExists (command_name))
+ {
+ result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
+ command_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+
+ if (interpreter->RemoveUser (command_name) == false)
+ {
+ if (interpreter->UserCommandExists (command_name))
+ result.AppendErrorWithFormat ("Unknown error occurred; unable to remove command '%s'.\n",
+ command_name);
+ else
+ result.AppendErrorWithFormat ("'%s' is not a user-defined command/function name.\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 remove with a valid command");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+}
+
diff --git a/lldb/source/Commands/CommandObjectRemove.h b/lldb/source/Commands/CommandObjectRemove.h
new file mode 100644
index 00000000000..4b017a4fbb1
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectRemove.h
@@ -0,0 +1,44 @@
+//===-- CommandObjectRemove.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectRemove_h_
+#define liblldb_CommandObjectRemove_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectRemove
+//-------------------------------------------------------------------------
+
+class CommandObjectRemove : public CommandObject
+{
+public:
+
+ CommandObjectRemove ();
+
+ virtual
+ ~CommandObjectRemove ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectRemove_h_
diff --git a/lldb/source/Commands/CommandObjectScript.cpp b/lldb/source/Commands/CommandObjectScript.cpp
new file mode 100644
index 00000000000..64864be8d09
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectScript.cpp
@@ -0,0 +1,149 @@
+//===-- 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 "CommandObjectScript.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+#include "lldb/Interpreter/ScriptInterpreterNone.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectScript
+//-------------------------------------------------------------------------
+
+CommandObjectScript::CommandObjectScript (ScriptLanguage script_lang) :
+ CommandObject ("script",
+ "Passes an expression to the script interpreter for evaluation and returns the results. Drops user into the interactive interpreter if no expressions are given.",
+ "script [<script-expressions-for-evaluation>]"),
+ m_script_lang (script_lang),
+ m_interpreter_ap ()
+{
+}
+
+CommandObjectScript::~CommandObjectScript ()
+{
+}
+
+bool
+CommandObjectScript::ExecuteRawCommandString
+(
+ const char *command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ std::string arg_str (command);
+
+ ScriptInterpreter *script_interpreter = GetInterpreter ();
+
+ if (script_interpreter == NULL)
+ {
+ result.AppendError("no script interpeter");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle();
+ FILE *err_fh = Debugger::GetSharedInstance().GetOutputFileHandle();
+ if (out_fh && err_fh)
+ {
+ if (arg_str.empty())
+ script_interpreter->ExecuteInterpreterLoop (out_fh, err_fh);
+ else
+ script_interpreter->ExecuteOneLine (arg_str, out_fh, err_fh);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ if (out_fh == NULL)
+ result.AppendError("invalid output file handle");
+ else
+ result.AppendError("invalid error file handle");
+ }
+ return result.Succeeded();
+}
+
+bool
+CommandObjectScript::WantsRawCommandString()
+{
+ return true;
+}
+
+bool
+CommandObjectScript::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ std::string arg_str;
+ ScriptInterpreter *script_interpreter = GetInterpreter ();
+
+ if (script_interpreter == NULL)
+ {
+ result.AppendError("no script interpeter");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ const int argc = command.GetArgumentCount();
+ for (int i = 0; i < argc; ++i)
+ arg_str.append(command.GetArgumentAtIndex(i));
+
+
+ FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle();
+ FILE *err_fh = Debugger::GetSharedInstance().GetOutputFileHandle();
+ if (out_fh && err_fh)
+ {
+ if (arg_str.empty())
+ script_interpreter->ExecuteInterpreterLoop (out_fh, err_fh);
+ else
+ script_interpreter->ExecuteOneLine (arg_str, out_fh, err_fh);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ if (out_fh == NULL)
+ result.AppendError("invalid output file handle");
+ else
+ result.AppendError("invalid error file handle");
+ }
+ return result.Succeeded();
+}
+
+
+ScriptInterpreter *
+CommandObjectScript::GetInterpreter ()
+{
+ if (m_interpreter_ap.get() == NULL)
+ {
+ switch (m_script_lang)
+ {
+ case eScriptLanguagePython:
+ m_interpreter_ap.reset (new ScriptInterpreterPython ());
+ break;
+
+ case eScriptLanguageNone:
+ m_interpreter_ap.reset (new ScriptInterpreterNone ());
+ break;
+ }
+ }
+ return m_interpreter_ap.get();
+}
diff --git a/lldb/source/Commands/CommandObjectScript.h b/lldb/source/Commands/CommandObjectScript.h
new file mode 100644
index 00000000000..7cd57518ff7
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectScript.h
@@ -0,0 +1,58 @@
+//===-- 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 CommandObject
+{
+public:
+
+ CommandObjectScript (lldb::ScriptLanguage script_lang);
+
+ virtual
+ ~CommandObjectScript ();
+
+ bool WantsRawCommandString();
+
+ virtual bool
+ ExecuteRawCommandString (const char *command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ ScriptInterpreter *
+ GetInterpreter ();
+
+private:
+ lldb::ScriptLanguage m_script_lang;
+ std::auto_ptr<ScriptInterpreter> m_interpreter_ap;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectScript_h_
diff --git a/lldb/source/Commands/CommandObjectSelect.cpp b/lldb/source/Commands/CommandObjectSelect.cpp
new file mode 100644
index 00000000000..f357cd290a2
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectSelect.cpp
@@ -0,0 +1,32 @@
+//===-- CommandObjectSelect.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectSelect.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectSelect
+//-------------------------------------------------------------------------
+
+CommandObjectSelect::CommandObjectSelect () :
+ CommandObjectCrossref ("select", "Lists the kinds of objects you can select, and shows syntax for selecting them.", "select")
+{
+}
+
+CommandObjectSelect::~CommandObjectSelect ()
+{
+}
+
+
diff --git a/lldb/source/Commands/CommandObjectSelect.h b/lldb/source/Commands/CommandObjectSelect.h
new file mode 100644
index 00000000000..18a64eba276
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectSelect.h
@@ -0,0 +1,37 @@
+//===-- CommandObjectSelect.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectSelect_h_
+#define liblldb_CommandObjectSelect_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectCrossref.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectSelect
+//-------------------------------------------------------------------------
+
+class CommandObjectSelect : public CommandObjectCrossref
+{
+public:
+ CommandObjectSelect ();
+
+ virtual
+ ~CommandObjectSelect ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectSelect_h_
diff --git a/lldb/source/Commands/CommandObjectSet.cpp b/lldb/source/Commands/CommandObjectSet.cpp
new file mode 100644
index 00000000000..46ad049fd1b
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectSet.cpp
@@ -0,0 +1,153 @@
+//===-- CommandObjectSet.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectSet.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;
+
+//-------------------------------------------------------------------------
+// CommandObjectSet
+//-------------------------------------------------------------------------
+
+CommandObjectSet::CommandObjectSet () :
+ CommandObject ("set",
+ "Allows the user to set or change the value of a single debugger setting variable.",
+ "set <setting_name> <value>")
+{
+}
+
+CommandObjectSet::~CommandObjectSet()
+{
+}
+
+
+bool
+CommandObjectSet::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ CommandInterpreter::VariableMap::iterator pos;
+
+ const int argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendError ("'set' takes at least two arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = command.GetArgumentAtIndex(0);
+ const char *var_value = command.GetArgumentAtIndex(1);
+
+ if (var_name == NULL || var_name[0] == '\0')
+ {
+ result.AppendError ("'set' command requires a valid variable name; No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else if (var_value == NULL || var_value[0] == '\0')
+ {
+ // No value given: Check to see if we're trying to clear an array.
+ StateVariable *var = interpreter->GetStateVariable (var_name);
+ if (var != NULL
+ && var->GetType() == StateVariable::eTypeStringArray)
+ {
+ var->ArrayClearValues();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("'set' command requires a valid variable value; No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ StateVariable *var = interpreter->GetStateVariable(var_name);
+ if (var == NULL)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a settable internal variable.\n", var_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ if (var->GetType() == StateVariable::eTypeBoolean)
+ {
+ bool success = false;
+ bool new_value = Args::StringToBoolean (var_value, false, &success);
+
+ if (success)
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ if (!var->HasVerifyFunction() || var->VerifyValue (interpreter, (void *) &new_value, result))
+ var->SetBoolValue (new_value);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid boolean string '%s'.\n", var_value);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else if (var->GetType() == StateVariable::eTypeInteger)
+ {
+ bool success = false;
+ int new_value = Args::StringToSInt32(var_value, -1, 0, &success);
+
+ if (success)
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ if (!var->HasVerifyFunction() || var->VerifyValue (interpreter, (void *) &new_value, result))
+ var->SetIntValue (new_value);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid boolean string '%s'.\n", var_value);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else if (var->GetType() == StateVariable::eTypeString)
+ {
+ if (!var->HasVerifyFunction() || var->VerifyValue (interpreter, (void *) var_value, result))
+ var->SetStringValue (var_value);
+ }
+ else if (var->GetType() == StateVariable::eTypeStringArray)
+ {
+ if (var_value == NULL || var_value[0] == '\0')
+ var->ArrayClearValues ();
+ else
+ {
+ command.Shift(); // shift off variable name
+ var->ArrayClearValues(); // clear the old values
+ var->GetArgs().AppendArguments (command); // set the new values.
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Variable '%s' has unrecognized type.\n",
+ var->GetName());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ return result.Succeeded();
+}
+
diff --git a/lldb/source/Commands/CommandObjectSet.h b/lldb/source/Commands/CommandObjectSet.h
new file mode 100644
index 00000000000..1a3c3dfd1bc
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectSet.h
@@ -0,0 +1,44 @@
+//===-- CommandObjectSet.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectSet_h_
+#define liblldb_CommandObjectSet_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectSet
+//-------------------------------------------------------------------------
+
+class CommandObjectSet : public CommandObject
+{
+public:
+
+ CommandObjectSet ();
+
+ virtual
+ ~CommandObjectSet ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectSet_h_
diff --git a/lldb/source/Commands/CommandObjectSettings.cpp b/lldb/source/Commands/CommandObjectSettings.cpp
new file mode 100644
index 00000000000..078b699ffdb
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectSettings.cpp
@@ -0,0 +1,62 @@
+//===-- 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 "CommandObjectSettings.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;
+
+//-------------------------------------------------------------------------
+// CommandObjectSettings
+//-------------------------------------------------------------------------
+
+CommandObjectSettings::CommandObjectSettings () :
+ CommandObject ("settings",
+ "Lists the debugger settings variables available to the user to 'set' or 'show'.",
+ "settings")
+{
+}
+
+CommandObjectSettings::~CommandObjectSettings()
+{
+}
+
+
+bool
+CommandObjectSettings::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ CommandInterpreter::VariableMap::iterator pos;
+
+ if (command.GetArgumentCount() != 0)
+ {
+ result.AppendError ("'settings' does not take any arguments");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ interpreter->ShowVariableHelp (result);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+}
+
diff --git a/lldb/source/Commands/CommandObjectSettings.h b/lldb/source/Commands/CommandObjectSettings.h
new file mode 100644
index 00000000000..674a98b8ca8
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectSettings.h
@@ -0,0 +1,44 @@
+//===-- 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"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectSettings
+//-------------------------------------------------------------------------
+
+class CommandObjectSettings : public CommandObject
+{
+public:
+
+ CommandObjectSettings ();
+
+ virtual
+ ~CommandObjectSettings ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectSettings_h_
diff --git a/lldb/source/Commands/CommandObjectShow.cpp b/lldb/source/Commands/CommandObjectShow.cpp
new file mode 100644
index 00000000000..be6f6888a99
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectShow.cpp
@@ -0,0 +1,74 @@
+//===-- CommandObjectShow.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectShow.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;
+
+//-------------------------------------------------------------------------
+// CommandObjectShow
+//-------------------------------------------------------------------------
+
+CommandObjectShow::CommandObjectShow () :
+ CommandObject ("show",
+ "Allows the user to see a single debugger setting variable and its value, or lists them all.",
+ "show [<setting-variable-name>]")
+{
+}
+
+CommandObjectShow::~CommandObjectShow()
+{
+}
+
+
+bool
+CommandObjectShow::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ CommandInterpreter::VariableMap::iterator pos;
+
+ if (command.GetArgumentCount())
+ {
+ // The user requested to see the value of a particular variable.
+
+ const char *var_name = command.GetArgumentAtIndex(0);
+ StateVariable *var = interpreter->GetStateVariable(var_name);
+ if (var)
+ {
+ var->AppendVariableInformation (result);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unrecognized variable '%s'; cannot do 'show' command.\n", var_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ // The user didn't specify a particular variable, so show the values of all of them.
+ interpreter->ShowVariableValues(result);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+}
diff --git a/lldb/source/Commands/CommandObjectShow.h b/lldb/source/Commands/CommandObjectShow.h
new file mode 100644
index 00000000000..460280a3c55
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectShow.h
@@ -0,0 +1,44 @@
+//===-- CommandObjectShow.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectShow_h_
+#define liblldb_CommandObjectShow_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectShow
+//-------------------------------------------------------------------------
+
+class CommandObjectShow : public CommandObject
+{
+public:
+
+ CommandObjectShow ();
+
+ virtual
+ ~CommandObjectShow ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectShow_h_
diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp
new file mode 100644
index 00000000000..e2c3a0a143f
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectSource.cpp
@@ -0,0 +1,127 @@
+//===-- 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 "CommandObjectSource.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Interpreter/CommandContext.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/TargetList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *k_space_characters = "\t\n\v\f\r ";
+
+//-------------------------------------------------------------------------
+// CommandObjectSource
+//-------------------------------------------------------------------------
+
+CommandObjectSource::CommandObjectSource() :
+ CommandObject ("source",
+ "Reads in debugger commands from the file <filename> and executes them.",
+ "source <filename>")
+{
+}
+
+CommandObjectSource::~CommandObjectSource ()
+{
+}
+
+bool
+CommandObjectSource::Execute
+(
+ Args& args,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ const int argc = args.GetArgumentCount();
+ if (argc == 1)
+ {
+ const char *filename = args.GetArgumentAtIndex(0);
+ bool success = true;
+
+ result.AppendMessageWithFormat ("Executing commands in '%s'.\n", filename);
+
+ FileSpec cmd_file (filename);
+ if (cmd_file.Exists())
+ {
+ STLStringArray commands;
+ success = cmd_file.ReadFileLines (commands);
+
+ STLStringArray::iterator pos = commands.begin();
+
+ // Trim out any empty lines or lines that start with the comment
+ // char '#'
+ while (pos != commands.end())
+ {
+ bool remove_string = false;
+ size_t non_space = pos->find_first_not_of (k_space_characters);
+ if (non_space == std::string::npos)
+ remove_string = true; // Empty line
+ else if ((*pos)[non_space] == '#')
+ remove_string = true; // Comment line that starts with '#'
+
+ if (remove_string)
+ pos = commands.erase(pos);
+ else
+ ++pos;
+ }
+
+ if (commands.size() > 0)
+ {
+ const size_t num_commands = commands.size();
+ size_t i;
+ for (i = 0; i<num_commands; ++i)
+ {
+ result.GetOutputStream().Printf("%s %s\n", interpreter->GetPrompt(), commands[i].c_str());
+ if (!interpreter->HandleCommand(commands[i].c_str(), false, result))
+ break;
+ }
+
+ if (i < num_commands)
+ {
+ result.AppendErrorWithFormat("Aborting source of '%s' after command '%s' failed.\n", filename, commands[i].c_str());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ success = true;
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("File '%s' does not exist.\n", filename);
+ result.SetStatus (eReturnStatusFailed);
+ success = false;
+ }
+
+ if (success)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+
+}
diff --git a/lldb/source/Commands/CommandObjectSource.h b/lldb/source/Commands/CommandObjectSource.h
new file mode 100644
index 00000000000..416e3c02b2c
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectSource.h
@@ -0,0 +1,48 @@
+//===-- CommandObjectSource.h -----------------------------------*- 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/Core/STLUtils.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectSource
+//-------------------------------------------------------------------------
+
+class CommandObjectSource : public CommandObject
+{
+public:
+
+ CommandObjectSource ();
+
+ virtual
+ ~CommandObjectSource ();
+
+ STLStringArray &
+ GetCommands ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectSource_h_
diff --git a/lldb/source/Commands/CommandObjectSourceFile.cpp b/lldb/source/Commands/CommandObjectSourceFile.cpp
new file mode 100644
index 00000000000..df70bc9aea3
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectSourceFile.cpp
@@ -0,0 +1,206 @@
+//===-- CommandObjectSourceFile.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectSourceFile.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Interpreter/CommandContext.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandObjectSourceFile::CommandOptions::CommandOptions () :
+ Options()
+{
+}
+
+CommandObjectSourceFile::CommandOptions::~CommandOptions ()
+{
+}
+
+Error
+CommandObjectSourceFile::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
+{
+ Error error;
+ const char 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'.\n", option_arg);
+ break;
+
+ case 'n':
+ num_lines = Args::StringToUInt32 (option_arg, 0);
+ if (num_lines == 0)
+ error.SetErrorStringWithFormat("Invalid line count: '%s'.\n", option_arg);
+ break;
+
+ case 'f':
+ file_name = option_arg;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectSourceFile::CommandOptions::ResetOptionValues ()
+{
+ Options::ResetOptionValues();
+
+ file_spec.Clear();
+ file_name.clear();
+ start_line = 0;
+ num_lines = 10;
+}
+
+const lldb::OptionDefinition*
+CommandObjectSourceFile::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+lldb::OptionDefinition
+CommandObjectSourceFile::CommandOptions::g_option_table[] =
+{
+{ 0, false, "line", 'l', required_argument, NULL, 0, "<line>", "The line number at which to start the display source."},
+{ 0, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, "<file>", "The file from which to display source."},
+{ 0, false, "count", 'n', required_argument, NULL, 0, "<count>", "The number of source lines to display."},
+{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+
+//-------------------------------------------------------------------------
+// CommandObjectSourceFile
+//-------------------------------------------------------------------------
+
+CommandObjectSourceFile::CommandObjectSourceFile() :
+ CommandObject ("source-file",
+ "Display source files from the current executable's debug info.",
+ "source-file [<cmd-options>] [<filename>]")
+{
+}
+
+CommandObjectSourceFile::~CommandObjectSourceFile ()
+{
+}
+
+
+Options *
+CommandObjectSourceFile::GetOptions ()
+{
+ return &m_options;
+}
+
+
+bool
+CommandObjectSourceFile::Execute
+(
+ Args& args,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ const int argc = args.GetArgumentCount();
+
+ if (argc != 0)
+ {
+ result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName());
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ ExecutionContext exe_ctx(context->GetExecutionContext());
+ 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 (interpreter->GetSourceManager().DisplayMoreWithLineNumbers (&result.GetOutputStream()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ }
+ else
+ {
+ if (interpreter->GetSourceManager().DisplaySourceLinesWithLineNumbersUsingLastFile(
+ m_options.start_line, // Line to display
+ 0, // Lines before line to display
+ m_options.num_lines, // Lines after line to display
+ "", // Don't mark "line"
+ &result.GetOutputStream()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+
+ }
+ }
+ else
+ {
+ const char *filename = m_options.file_name.c_str();
+ Target *target = context->GetTarget();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, set executable file using 'file' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+
+ bool check_inlines = false;
+ SymbolContextList sc_list;
+ size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (filename,
+ 0,
+ check_inlines,
+ eSymbolContextModule | eSymbolContextCompUnit,
+ sc_list);
+ if (num_matches > 0)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ if (sc.comp_unit)
+ {
+ interpreter->GetSourceManager ().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
+ m_options.start_line, // Line to display
+ 0, // Lines before line to display
+ m_options.num_lines, // Lines after line to display
+ "", // Don't mark "line"
+ &result.GetOutputStream());
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ }
+ }
+ }
+ }
+
+ return result.Succeeded();
+}
+
diff --git a/lldb/source/Commands/CommandObjectSourceFile.h b/lldb/source/Commands/CommandObjectSourceFile.h
new file mode 100644
index 00000000000..ba12f0f753c
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectSourceFile.h
@@ -0,0 +1,80 @@
+//===-- CommandObjectSourceFile.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectSourceFile_h_
+#define liblldb_CommandObjectSourceFile_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Core/FileSpec.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectSourceFile
+//-------------------------------------------------------------------------
+
+class CommandObjectSourceFile : public CommandObject
+{
+public:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions ();
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg);
+
+ void
+ ResetOptionValues ();
+
+ const lldb::OptionDefinition*
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ FileSpec file_spec;
+ std::string file_name;
+ uint32_t start_line;
+ uint32_t num_lines;
+ };
+
+ CommandObjectSourceFile ();
+
+ virtual
+ ~CommandObjectSourceFile ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual
+ Options *
+ GetOptions ();
+
+protected:
+ CommandOptions m_options;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectSourceFile_h_
diff --git a/lldb/source/Commands/CommandObjectStatus.cpp b/lldb/source/Commands/CommandObjectStatus.cpp
new file mode 100644
index 00000000000..501e0b23c84
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectStatus.cpp
@@ -0,0 +1,97 @@
+//===-- CommandObjectStatus.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectStatus.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "CommandObjectThread.h"
+
+#include "lldb/Core/State.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectStatus
+//-------------------------------------------------------------------------
+
+CommandObjectStatus::CommandObjectStatus () :
+ CommandObject ("status",
+ "Shows the current status and location of executing process.",
+ "status",
+ 0)
+{
+}
+
+CommandObjectStatus::~CommandObjectStatus()
+{
+}
+
+
+bool
+CommandObjectStatus::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ StreamString &output_stream = result.GetOutputStream();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ ExecutionContext exe_ctx(context->GetExecutionContext());
+ if (exe_ctx.process)
+ {
+ const StateType state = exe_ctx.process->GetState();
+ if (StateIsStoppedState(state))
+ {
+ if (state == eStateExited)
+ {
+ int exit_status = exe_ctx.process->GetExitStatus();
+ const char *exit_description = exe_ctx.process->GetExitDescription();
+ output_stream.Printf ("Process %d exited with status = %i (0x%8.8x) %s\n",
+ exe_ctx.process->GetID(),
+ exit_status,
+ exit_status,
+ exit_description ? exit_description : "");
+ }
+ else
+ {
+ output_stream.Printf ("Process %d %s\n", exe_ctx.process->GetID(), StateAsCString (state));
+ if (exe_ctx.thread == NULL)
+ exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get();
+ if (exe_ctx.thread != NULL)
+ {
+ DisplayThreadsInfo (interpreter, &exe_ctx, result, true, true);
+ }
+ else
+ {
+ result.AppendError ("No valid thread found in current process.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("No current location or status available.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+}
+
diff --git a/lldb/source/Commands/CommandObjectStatus.h b/lldb/source/Commands/CommandObjectStatus.h
new file mode 100644
index 00000000000..da5fa7b7097
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectStatus.h
@@ -0,0 +1,44 @@
+//===-- CommandObjectStatus.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectStatus_h_
+#define liblldb_CommandObjectStatus_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectStatus
+//-------------------------------------------------------------------------
+
+class CommandObjectStatus : public CommandObject
+{
+public:
+
+ CommandObjectStatus ();
+
+ ~CommandObjectStatus ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectStatus_h_
diff --git a/lldb/source/Commands/CommandObjectSyntax.cpp b/lldb/source/Commands/CommandObjectSyntax.cpp
new file mode 100644
index 00000000000..b1fc42f7637
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectSyntax.cpp
@@ -0,0 +1,148 @@
+//===-- 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 "CommandObjectSyntax.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/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 () :
+ CommandObject ("syntax",
+ "Shows the correct syntax for a given debugger command.",
+ "syntax <command>")
+{
+}
+
+CommandObjectSyntax::~CommandObjectSyntax()
+{
+}
+
+
+bool
+CommandObjectSyntax::OldExecute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ CommandObject *cmd_obj;
+
+ if (command.GetArgumentCount() != 0)
+ {
+ cmd_obj = interpreter->GetCommandObject(command.GetArgumentAtIndex(0));
+ if (cmd_obj)
+ {
+ Stream &output_strm = result.GetOutputStream();
+ if (cmd_obj->GetOptions() != NULL)
+ {
+ output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax());
+ //cmd_obj->GetOptions()->GenerateOptionUsage (output_strm, cmd_obj);
+ 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
+ {
+ result.AppendErrorWithFormat ("'%s' is not a known command.\n", command.GetArgumentAtIndex(0));
+ 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();
+}
+
+bool
+CommandObjectSyntax::Execute (Args &command, CommandContext *context, CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+{
+ CommandObject::CommandMap::iterator pos;
+ CommandObject *cmd_obj;
+ const int argc = command.GetArgumentCount();
+
+ if (argc > 0)
+ {
+ cmd_obj = interpreter->GetCommandObject (command.GetArgumentAtIndex(0));
+ bool all_okay = true;
+ for (int i = 1; i < argc; ++i)
+ {
+ std::string sub_command = command.GetArgumentAtIndex (i);
+ if (! cmd_obj->IsMultiwordObject())
+ all_okay = false;
+ else
+ {
+ pos = ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict.find (sub_command);
+ if (pos != ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict.end())
+ cmd_obj = pos->second.get();
+ else
+ 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());
+ //cmd_obj->GetOptions()->GenerateOptionUsage (output_strm, cmd_obj);
+ 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/lldb/source/Commands/CommandObjectSyntax.h b/lldb/source/Commands/CommandObjectSyntax.h
new file mode 100644
index 00000000000..e5f5f4e544d
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectSyntax.h
@@ -0,0 +1,51 @@
+//===-- 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 CommandObject
+{
+public:
+
+ CommandObjectSyntax ();
+
+ virtual
+ ~CommandObjectSyntax ();
+
+ bool
+ OldExecute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectSyntax_h_
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
new file mode 100644
index 00000000000..5ea240e301f
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -0,0 +1,430 @@
+//===-- 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 "CommandObjectTarget.h"
+
+// C Includes
+#include <errno.h>
+#include <sys/errno.h>
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Interpreter/CommandContext.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#pragma mark CommandObjectTargetImageSearchPaths
+
+class CommandObjectTargetImageSearchPathsAdd : public CommandObject
+{
+public:
+
+ CommandObjectTargetImageSearchPathsAdd () :
+ CommandObject ("target image-search-paths add",
+ "Add new image search paths substitution pairs to the current target.",
+ "target image-search-paths add <path-prefix> <new-path-prefix> [<path-prefix> <new-path-prefix>] ...")
+ {
+ }
+
+ ~CommandObjectTargetImageSearchPathsAdd ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target * target = context->GetTarget();
+ if (target)
+ {
+ uint32_t argc = command.GetArgumentCount();
+ if (argc & 1)
+ {
+ result.AppendError ("add requires an even number of arguments");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ for (uint32_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
+ }
+ else
+ {
+ if (from[0])
+ result.AppendError ("<path-prefix> can't be empty");
+ else
+ result.AppendError ("<new-path-prefix> can't be empty");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid target");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+class CommandObjectTargetImageSearchPathsClear : public CommandObject
+{
+public:
+
+ CommandObjectTargetImageSearchPathsClear () :
+ CommandObject ("target image-search-paths clear",
+ "Clears all current image search paths substitution pairs from the current target.",
+ "target image-search-paths clear")
+ {
+ }
+
+ ~CommandObjectTargetImageSearchPathsClear ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target * target = context->GetTarget();
+ if (target)
+ {
+ bool notify = true;
+ target->GetImageSearchPathList().Clear(notify);
+ }
+ else
+ {
+ result.AppendError ("invalid target");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+class CommandObjectTargetImageSearchPathsInsert : public CommandObject
+{
+public:
+
+ CommandObjectTargetImageSearchPathsInsert () :
+ CommandObject ("target image-search-paths insert",
+ "Inserts a new image search paths substitution pair to the current target at the specified index.",
+ "target image-search-paths insert <index> <path-prefix> <new-path-prefix> [<path-prefix> <new-path-prefix>] ...")
+ {
+ }
+
+ ~CommandObjectTargetImageSearchPathsInsert ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target * target = context->GetTarget();
+ if (target)
+ {
+ uint32_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);
+ }
+ else
+ {
+ if (from[0])
+ result.AppendError ("<path-prefix> can't be empty");
+ else
+ result.AppendError ("<new-path-prefix> can't be empty");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("insert requires at least three arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ }
+ else
+ {
+ result.AppendError ("invalid target");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+class CommandObjectTargetImageSearchPathsList : public CommandObject
+{
+public:
+
+ CommandObjectTargetImageSearchPathsList () :
+ CommandObject ("target image-search-paths list",
+ "Lists all current image search paths substitution pairs in the current target.",
+ "target image-search-paths list")
+ {
+ }
+
+ ~CommandObjectTargetImageSearchPathsList ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target * target = context->GetTarget();
+ if (target)
+ {
+ if (command.GetArgumentCount() != 0)
+ {
+ result.AppendError ("list takes no arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ target->GetImageSearchPathList().Dump(&result.GetOutputStream());
+ }
+ else
+ {
+ result.AppendError ("invalid target");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+class CommandObjectTargetImageSearchPathsQuery : public CommandObject
+{
+public:
+
+ CommandObjectTargetImageSearchPathsQuery () :
+ CommandObject ("target image-search-paths query",
+ "Transforms a path using the first applicable image search path.",
+ "target image-search-paths query <path>")
+ {
+ }
+
+ ~CommandObjectTargetImageSearchPathsQuery ()
+ {
+ }
+
+ bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Target * target = context->GetTarget();
+ if (target)
+ {
+ if (command.GetArgumentCount() != 1)
+ {
+ result.AppendError ("query requires one argument");
+ 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());
+ }
+ else
+ {
+ result.AppendError ("invalid target");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+// TODO: implement the target select later when we start doing multiple targets
+//#pragma mark CommandObjectTargetSelect
+//
+////-------------------------------------------------------------------------
+//// CommandObjectTargetSelect
+////-------------------------------------------------------------------------
+//
+//class CommandObjectTargetSelect : public CommandObject
+//{
+//public:
+//
+// CommandObjectTargetSelect () :
+// CommandObject ("frame select",
+// "Select the current frame by index in the current thread.",
+// "frame select <frame-index>")
+// {
+// }
+//
+// ~CommandObjectTargetSelect ()
+// {
+// }
+//
+// bool
+// Execute (Args& command,
+// CommandContext *context,
+// CommandInterpreter *interpreter,
+// CommandReturnObject &result)
+// {
+// ExecutionContext exe_ctx (context->GetExecutionContext());
+// if (exe_ctx.thread)
+// {
+// if (command.GetArgumentCount() == 1)
+// {
+// const char *frame_idx_cstr = command.GetArgumentAtIndex(0);
+//
+// const uint32_t num_frames = exe_ctx.thread->GetStackFrameCount();
+// const uint32_t frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0);
+// if (frame_idx < num_frames)
+// {
+// exe_ctx.thread->SetCurrentFrameByIndex (frame_idx);
+// exe_ctx.frame = exe_ctx.thread->GetCurrentFrame ().get();
+//
+// if (exe_ctx.frame)
+// {
+// if (DisplayFrameForExecutionContext (exe_ctx.thread,
+// exe_ctx.frame,
+// interpreter,
+// result.GetOutputStream(),
+// true,
+// true,
+// 3,
+// 3))
+// {
+// result.SetStatus (eReturnStatusSuccessFinishResult);
+// return result.Succeeded();
+// }
+// }
+// }
+// if (frame_idx == UINT32_MAX)
+// result.AppendErrorWithFormat ("Invalid frame index: %s.\n", frame_idx_cstr);
+// else
+// result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx);
+// }
+// else
+// {
+// result.AppendError ("invalid arguments");
+// result.AppendErrorWithFormat ("Usage: %s\n", m_cmd_syntax.c_str());
+// }
+// }
+// else
+// {
+// result.AppendError ("no current thread");
+// }
+// result.SetStatus (eReturnStatusFailed);
+// return false;
+// }
+//};
+
+
+#pragma mark CommandObjectMultiwordTarget
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordImageSearchPaths
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordImageSearchPaths : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordImageSearchPaths (CommandInterpreter *interpreter) :
+ CommandObjectMultiword ("target image-search-paths",
+ "A set of commands for operating on debugger target image search paths.",
+ "target image-search-paths <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand (CommandObjectSP (new CommandObjectTargetImageSearchPathsAdd ()), "add", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectTargetImageSearchPathsClear ()), "clear", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectTargetImageSearchPathsInsert ()), "insert", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectTargetImageSearchPathsList ()), "list", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectTargetImageSearchPathsQuery ()), "query", interpreter);
+ }
+
+ ~CommandObjectMultiwordImageSearchPaths()
+ {
+ }
+};
+
+
+#pragma mark CommandObjectMultiwordTarget
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordTarget
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordTarget::CommandObjectMultiwordTarget (CommandInterpreter *interpreter) :
+ CommandObjectMultiword ("target",
+ "A set of commands for operating on debugger targets.",
+ "target <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand (CommandObjectSP (new CommandObjectMultiwordImageSearchPaths (interpreter)), "image-search-paths", interpreter);
+}
+
+CommandObjectMultiwordTarget::~CommandObjectMultiwordTarget ()
+{
+}
+
diff --git a/lldb/source/Commands/CommandObjectTarget.h b/lldb/source/Commands/CommandObjectTarget.h
new file mode 100644
index 00000000000..cd569e1821d
--- /dev/null
+++ b/lldb/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/Core/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/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
new file mode 100644
index 00000000000..07777a19cfe
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -0,0 +1,1277 @@
+//===-- 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 "CommandObjectThread.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Options.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/SourceManager.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.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/ThreadPlanContinue.h"
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepRange.h"
+#include "lldb/Target/ThreadPlanStepInRange.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/LineEntry.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+bool
+lldb_private::DisplayThreadInfo
+(
+ CommandInterpreter *interpreter,
+ Stream &strm,
+ Thread *thread,
+ bool only_threads_with_stop_reason,
+ bool show_source
+)
+{
+ if (thread)
+ {
+ if (only_threads_with_stop_reason)
+ {
+ StopReason thread_stop_reason = eStopReasonNone;
+ Thread::StopInfo thread_stop_info;
+ if (thread->GetStopInfo(&thread_stop_info))
+ {
+ thread_stop_reason = thread_stop_info.GetStopReason();
+ if (thread_stop_reason == eStopReasonNone)
+ return false;
+ }
+ }
+
+ strm.Indent();
+ strm.Printf("%c ", thread->GetProcess().GetThreadList().GetCurrentThread().get() == thread ? '*' : ' ');
+
+ // Show one frame with only the first showing source
+ if (show_source)
+ {
+ DisplayFramesForExecutionContext (thread,
+ interpreter,
+ strm,
+ true,
+ 0, // Start at first frame
+ 1, // Number of frames to show
+ false,// Don't show the frame info since we already displayed most of it above...
+ 1, // Show source for the first frame
+ 3, // lines of source context before
+ 3); // lines of source context after
+ }
+ else
+ {
+ thread->DumpInfo (strm,
+ true, // Dump the stop reason?
+ true, // Dump the thread name?
+ true, // Dump the queue name?
+ 0); // Display context info for stack frame zero
+
+ strm.EOL();
+ }
+
+ return true;
+ }
+ return false;
+}
+
+size_t
+lldb_private::DisplayThreadsInfo
+(
+ CommandInterpreter *interpreter,
+ ExecutionContext *exe_ctx,
+ CommandReturnObject &result,
+ bool only_threads_with_stop_reason,
+ bool show_source
+)
+{
+ StreamString strm;
+
+ size_t num_thread_infos_dumped = 0;
+
+ if (!exe_ctx->process)
+ return 0;
+
+ const size_t num_threads = exe_ctx->process->GetThreadList().GetSize();
+ if (num_threads > 0)
+ {
+
+ for (uint32_t i = 0; i < num_threads; i++)
+ {
+ Thread *thread = exe_ctx->process->GetThreadList().GetThreadAtIndex(i).get();
+ if (thread)
+ {
+ if (DisplayThreadInfo (interpreter,
+ strm,
+ thread,
+ only_threads_with_stop_reason,
+ show_source))
+ ++num_thread_infos_dumped;
+ }
+ }
+ }
+
+ if (num_thread_infos_dumped > 0)
+ {
+ if (num_thread_infos_dumped < num_threads)
+ result.GetOutputStream().Printf("%u of %u threads stopped with reasons:\n", num_thread_infos_dumped, num_threads);
+
+ result.GetOutputStream().GetString().append(strm.GetString());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ return num_thread_infos_dumped;
+}
+
+
+size_t
+lldb_private::DisplayFramesForExecutionContext
+(
+ Thread *thread,
+ CommandInterpreter *interpreter,
+ Stream& strm,
+ bool ascending,
+ uint32_t first_frame,
+ uint32_t num_frames,
+ bool show_frame_info,
+ uint32_t num_frames_with_source,
+ uint32_t source_lines_before,
+ uint32_t source_lines_after
+)
+{
+ if (thread == NULL)
+ return 0;
+
+ size_t num_frames_displayed = 0;
+
+ if (num_frames == 0)
+ return 0;
+
+ thread->DumpInfo (strm,
+ true, // Dump the stop reason?
+ true, // Dump the thread name?
+ true, // Dump the queue name?
+ 0); // Dump info for stack frame zero
+ strm.EOL();
+ strm.IndentMore();
+
+ StackFrameSP frame_sp;
+ int frame_idx = 0;
+
+ if (ascending)
+ {
+ for (frame_idx = first_frame; frame_idx < first_frame + num_frames; ++frame_idx)
+ {
+ frame_sp = thread->GetStackFrameAtIndex (frame_idx);
+ if (frame_sp.get() == NULL)
+ break;
+
+ if (DisplayFrameForExecutionContext (thread,
+ frame_sp.get(),
+ interpreter,
+ strm,
+ show_frame_info,
+ num_frames_with_source > first_frame - frame_idx,
+ source_lines_before,
+ source_lines_after) == false)
+ break;
+
+ ++num_frames_displayed;
+ }
+ }
+ else
+ {
+ for (frame_idx = first_frame + num_frames - 1; frame_idx >= first_frame; --frame_idx)
+ {
+ frame_sp = thread->GetStackFrameAtIndex (frame_idx);
+ if (frame_sp == NULL)
+ break;
+
+ if (DisplayFrameForExecutionContext (thread,
+ frame_sp.get(),
+ interpreter,
+ strm,
+ show_frame_info,
+ num_frames_with_source > first_frame - frame_idx,
+ source_lines_before,
+ source_lines_after) == false)
+ break;
+
+ ++num_frames_displayed;
+ }
+ }
+ strm.IndentLess();
+ return num_frames_displayed;
+}
+
+bool
+lldb_private::DisplayFrameForExecutionContext
+(
+ Thread *thread,
+ StackFrame *frame,
+ CommandInterpreter *interpreter,
+ Stream& strm,
+ bool show_frame_info,
+ bool show_source,
+ uint32_t source_lines_before,
+ uint32_t source_lines_after
+)
+{
+ // thread and frame must be filled in prior to calling this function
+ if (thread && frame)
+ {
+ if (show_frame_info)
+ {
+ strm.Indent();
+ frame->Dump (&strm, true);
+ strm.EOL();
+ }
+
+ SymbolContext sc (frame->GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry));
+
+ if (show_source && sc.comp_unit && sc.line_entry.IsValid())
+ {
+ interpreter->GetSourceManager().DisplaySourceLinesWithLineNumbers (
+ sc.line_entry.file,
+ sc.line_entry.line,
+ 3,
+ 3,
+ "->",
+ &strm);
+
+ }
+ return true;
+ }
+ return false;
+}
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadBacktrace
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadBacktrace : public CommandObject
+{
+public:
+
+ CommandObjectThreadBacktrace () :
+ CommandObject ("thread backtrace",
+ "Shows the stack for one or more threads.",
+ "thread backtrace [<thread-idx>] ...",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
+ m_ascending (true)
+ {
+ }
+
+ ~CommandObjectThreadBacktrace()
+ {
+ }
+
+
+ bool
+ Execute
+ (
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+ )
+ {
+ if (command.GetArgumentCount() == 0)
+ {
+ ExecutionContext exe_ctx(context->GetExecutionContext());
+ if (exe_ctx.thread)
+ {
+ bool show_frame_info = true;
+ uint32_t num_frames_with_source = 0; // Don't show any frasmes with source when backtracing
+ if (DisplayFramesForExecutionContext (exe_ctx.thread,
+ interpreter,
+ result.GetOutputStream(),
+ m_ascending,
+ 0,
+ UINT32_MAX,
+ show_frame_info,
+ num_frames_with_source,
+ 3,
+ 3))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid thread");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("backtrace doesn't take arguments (for now)");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+protected:
+ bool m_ascending;
+};
+
+
+typedef enum StepScope
+{
+ eStepScopeSource,
+ eStepScopeInstruction
+};
+
+class CommandObjectThreadStepWithTypeAndScope : public CommandObject
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions () :
+ Options()
+ {
+ // Keep default values of all options in one place: ResetOptionValues ()
+ ResetOptionValues ();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg)
+ {
+ Error error;
+ char short_option = (char) 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'.\n", short_option);
+ }
+ break;
+ case 'm':
+ {
+ bool found_one = false;
+ OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
+ m_run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one);
+ if (!found_one)
+ error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option);
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ ResetOptionValues ()
+ {
+ Options::ResetOptionValues();
+ m_avoid_no_debug = true;
+ m_run_mode = eOnlyDuringStepping;
+ }
+
+ const lldb::OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ bool m_avoid_no_debug;
+ RunMode m_run_mode;
+ };
+
+ CommandObjectThreadStepWithTypeAndScope (const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags,
+ StepType step_type,
+ StepScope step_scope) :
+ CommandObject (name, help, syntax, flags),
+ m_step_type (step_type),
+ m_step_scope (step_scope),
+ m_options ()
+ {
+ }
+
+ virtual
+ ~CommandObjectThreadStepWithTypeAndScope ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Process *process = context->GetExecutionContext().process;
+ bool synchronous_execution = interpreter->GetSynchronous();
+
+ if (process == NULL)
+ {
+ result.AppendError ("need a valid process to step");
+ result.SetStatus (eReturnStatusFailed);
+
+ }
+ else
+ {
+ const uint32_t num_threads = process->GetThreadList().GetSize();
+ Thread *thread = NULL;
+
+ if (command.GetArgumentCount() == 0)
+ {
+ thread = process->GetThreadList().GetCurrentThread().get();
+ if (thread == NULL)
+ {
+ result.AppendError ("no current 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, 0, 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
+ bool_stop_other_threads = true;
+
+ if (m_step_type == eStepTypeInto)
+ {
+ StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+ ThreadPlan *new_plan;
+
+ if (frame->HasDebugInformation ())
+ {
+ new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, m_step_type,
+ frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
+ frame->GetSymbolContext(eSymbolContextEverything),
+ stop_other_threads);
+ if (new_plan)
+ {
+ ThreadPlanStepInRange *real_plan = dynamic_cast<ThreadPlanStepInRange *> (new_plan);
+ if (real_plan)
+ {
+ if (m_options.m_avoid_no_debug)
+ {
+ real_plan->GetFlags().Set (ThreadPlanShouldStopHere::eAvoidNoDebug);
+ }
+ else
+ {
+ real_plan->GetFlags().Clear (ThreadPlanShouldStopHere::eAvoidNoDebug);
+ }
+ }
+ }
+ }
+ else
+ new_plan = thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads);
+
+ process->GetThreadList().SetCurrentThreadByID (thread->GetID());
+ process->Resume ();
+ }
+ else if (m_step_type == eStepTypeOver)
+ {
+ StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+ ThreadPlan *new_plan;
+
+ if (frame->HasDebugInformation())
+ new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans,
+ m_step_type,
+ frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
+ frame->GetSymbolContext(eSymbolContextEverything),
+ stop_other_threads);
+ else
+ new_plan = thread->QueueThreadPlanForStepSingleInstruction (true,
+ abort_other_plans,
+ bool_stop_other_threads);
+
+ // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over.
+ // Maybe there should be a parameter to control this.
+ new_plan->SetOkayToDiscard(false);
+
+ process->GetThreadList().SetCurrentThreadByID (thread->GetID());
+ process->Resume ();
+ }
+ else if (m_step_type == eStepTypeTrace)
+ {
+ thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads);
+ process->GetThreadList().SetCurrentThreadByID (thread->GetID());
+ process->Resume ();
+ }
+ else if (m_step_type == eStepTypeTraceOver)
+ {
+ thread->QueueThreadPlanForStepSingleInstruction (true, abort_other_plans, bool_stop_other_threads);
+ process->GetThreadList().SetCurrentThreadByID (thread->GetID());
+ process->Resume ();
+ }
+ else if (m_step_type == eStepTypeOut)
+ {
+ ThreadPlan *new_plan;
+
+ new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, bool_stop_other_threads, eVoteYes, eVoteNoOpinion);
+ // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over.
+ // Maybe there should be a parameter to control this.
+ new_plan->SetOkayToDiscard(false);
+
+ process->GetThreadList().SetCurrentThreadByID (thread->GetID());
+ process->Resume ();
+ }
+ else
+ {
+ result.AppendError ("step type is not supported");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ 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().SetCurrentThreadByID (thread->GetID());
+ result.SetDidChangeProcessState (true);
+ result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ return result.Succeeded();
+ }
+
+protected:
+ StepType m_step_type;
+ StepScope m_step_scope;
+ CommandOptions m_options;
+};
+
+static lldb::OptionEnumValueElement
+g_tri_running_mode[] =
+{
+{ eOnlyThisThread, "thisThread", "Run only this thread"},
+{ eAllThreads, "allThreads", "Run all threads"},
+{ eOnlyDuringStepping, "whileStepping", "Run only this thread while stepping"},
+{ 0, NULL, NULL }
+};
+
+static lldb::OptionEnumValueElement
+g_duo_running_mode[] =
+{
+{ eOnlyThisThread, "thisThread", "Run only this thread"},
+{ eAllThreads, "allThreads", "Run all threads"},
+{ 0, NULL, NULL }
+};
+
+lldb::OptionDefinition
+CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] =
+{
+{ 0, true, "avoid_no_debug", 'a', required_argument, NULL, 0, "<avoid_no_debug>", "Should step-in step over functions with no debug information"},
+{ 0, true, "run_mode", 'm', required_argument, g_tri_running_mode, 0, "<run_mode>", "Determine how to run other threads while stepping this one"},
+{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadContinue
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadContinue : public CommandObject
+{
+public:
+
+ CommandObjectThreadContinue () :
+ CommandObject ("thread continue",
+ "Continues execution of one or more threads in an active process.",
+ "thread continue <thread-index> [<thread-index> ...]",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+ {
+ }
+
+
+ virtual
+ ~CommandObjectThreadContinue ()
+ {
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ bool synchronous_execution = interpreter->GetSynchronous ();
+
+ if (!context->GetTarget())
+ {
+ result.AppendError ("invalid target, set executable file using 'file' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Process *process = context->GetExecutionContext().process;
+ 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))
+ {
+ const uint32_t num_threads = process->GetThreadList().GetSize();
+ uint32_t idx;
+ const size_t argc = command.GetArgumentCount();
+ if (argc > 0)
+ {
+ std::vector<uint32_t> resume_thread_indexes;
+ for (uint32_t i=0; i<argc; ++i)
+ {
+ idx = Args::StringToUInt32 (command.GetArgumentAtIndex(0), LLDB_INVALID_INDEX32);
+ if (idx < num_threads)
+ resume_thread_indexes.push_back(idx);
+ else
+ result.AppendWarningWithFormat("Thread index %u out of range.\n", idx);
+ }
+
+ if (resume_thread_indexes.empty())
+ {
+ result.AppendError ("no valid thread indexes were specified");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ result.AppendMessage ("Resuming thread ");
+ for (idx=0; idx<num_threads; ++idx)
+ {
+ Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
+ if (find(resume_thread_indexes.begin(), resume_thread_indexes.end(), idx) != resume_thread_indexes.end())
+ {
+ result.AppendMessageWithFormat ("%u ", idx);
+ thread->SetResumeState (eStateRunning);
+ }
+ else
+ {
+ thread->SetResumeState (eStateSuspended);
+ }
+ }
+ result.AppendMessageWithFormat ("in process %i\n", process->GetID());
+ }
+ }
+ else
+ {
+ Thread *current_thread = process->GetThreadList().GetCurrentThread().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 (idx=0; idx<num_threads; ++idx)
+ {
+ Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
+ if (thread == current_thread)
+ {
+ result.AppendMessageWithFormat ("Resuming thread 0x%4.4x in process %i\n", thread->GetID(), process->GetID());
+ thread->SetResumeState (eStateRunning);
+ }
+ else
+ {
+ thread->SetResumeState (eStateSuspended);
+ }
+ }
+ }
+
+ Error error (process->Resume());
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID());
+ if (synchronous_execution)
+ {
+ StateType state = process->WaitForProcessToStop (NULL);
+
+ result.SetDidChangeProcessState (true);
+ result.AppendMessageWithFormat ("Process %i %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 CommandObject
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+ uint32_t m_thread_idx;
+ uint32_t m_frame_idx;
+
+ CommandOptions () :
+ Options(),
+ m_thread_idx(LLDB_INVALID_THREAD_ID),
+ m_frame_idx(LLDB_INVALID_FRAME_ID)
+ {
+ // Keep default values of all options in one place: ResetOptionValues ()
+ ResetOptionValues ();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg)
+ {
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 't':
+ {
+ uint32_t m_thread_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_INDEX32);
+ if (m_thread_idx == LLDB_INVALID_INDEX32)
+ {
+ error.SetErrorStringWithFormat ("Invalid thread index '%s'.\n", 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'.\n", option_arg);
+ }
+ }
+ break;
+ case 'm':
+ {
+ bool found_one = false;
+ OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
+ lldb::RunMode run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one);
+
+ if (!found_one)
+ error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option);
+ else if (run_mode == eAllThreads)
+ m_stop_others = false;
+ else
+ m_stop_others = true;
+
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ ResetOptionValues ()
+ {
+ Options::ResetOptionValues();
+ m_thread_idx = LLDB_INVALID_THREAD_ID;
+ m_frame_idx = 0;
+ m_stop_others = false;
+ }
+
+ const lldb::OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ uint32_t m_step_thread_idx;
+ bool m_stop_others;
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ };
+
+ CommandObjectThreadUntil () :
+ CommandObject ("thread until",
+ "Runs the current or specified thread until it reaches a given line number or leaves the current function.",
+ "thread until [<cmd-options>] <line-number>",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
+ m_options ()
+ {
+ }
+
+
+ virtual
+ ~CommandObjectThreadUntil ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ bool synchronous_execution = interpreter->GetSynchronous ();
+
+ if (!context->GetTarget())
+ {
+ result.AppendError ("invalid target, set executable file using 'file' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Process *process = context->GetExecutionContext().process;
+ 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().GetCurrentThread().get();
+ }
+ else
+ {
+ thread = process->GetThreadList().GetThreadAtIndex(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, 0, num_threads);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const bool abort_other_plans = true;
+
+ 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;
+ }
+
+ ThreadPlan *new_plan;
+
+ 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);
+
+ while (index_ptr <= end_ptr)
+ {
+ LineEntry line_entry;
+ index_ptr = sc.comp_unit->FindLineEntry(index_ptr, line_number, sc.comp_unit, &line_entry);
+ if (index_ptr == UINT32_MAX)
+ break;
+
+ addr_t address = line_entry.range.GetBaseAddress().GetLoadAddress(process);
+ if (address != LLDB_INVALID_ADDRESS)
+ address_list.push_back (address);
+ index_ptr++;
+ }
+
+ new_plan = thread->QueueThreadPlanForStepUntil (abort_other_plans, address_list.data(), address_list.size(), m_options.m_stop_others);
+ new_plan->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().SetCurrentThreadByID (m_options.m_thread_idx);
+ Error error (process->Resume ());
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID());
+ if (synchronous_execution)
+ {
+ StateType state = process->WaitForProcessToStop (NULL);
+
+ result.SetDidChangeProcessState (true);
+ result.AppendMessageWithFormat ("Process %i %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();
+ }
+protected:
+ CommandOptions m_options;
+
+};
+
+lldb::OptionDefinition
+CommandObjectThreadUntil::CommandOptions::g_option_table[] =
+{
+{ 0, true, "frame", 'f', required_argument, NULL, 0, "<frame>", "Frame index for until operation - defaults to 0"},
+{ 0, true, "thread", 't', required_argument, NULL, 0, "<thread>", "Thread index for the thread for until operation"},
+{ 0, true, "run_mode", 'm', required_argument, g_duo_running_mode, 0, "<run_mode>", "Determine how to run other threads while stepping this one"},
+{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadSelect
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadSelect : public CommandObject
+{
+public:
+
+ CommandObjectThreadSelect () :
+ CommandObject ("thread select",
+ "Selects a threads as the currently active thread.",
+ "thread select <thread-index>",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+ {
+ }
+
+
+ virtual
+ ~CommandObjectThreadSelect ()
+ {
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ Process *process = context->GetExecutionContext().process;
+ 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: \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().SetCurrentThreadByID(new_thread->GetID());
+
+ DisplayThreadInfo (interpreter,
+ result.GetOutputStream(),
+ new_thread,
+ false,
+ true);
+
+ return result.Succeeded();
+ }
+
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadList
+//-------------------------------------------------------------------------
+
+CommandObjectThreadList::CommandObjectThreadList ():
+ CommandObject ("thread list",
+ "Shows a summary of all current threads in a process.",
+ "thread list",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+{
+}
+
+CommandObjectThreadList::~CommandObjectThreadList()
+{
+}
+
+bool
+CommandObjectThreadList::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ StreamString &strm = result.GetOutputStream();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ ExecutionContext exe_ctx(context->GetExecutionContext());
+ if (exe_ctx.process)
+ {
+ const StateType state = exe_ctx.process->GetState();
+
+ if (StateIsStoppedState(state))
+ {
+ if (state == eStateExited)
+ {
+ int exit_status = exe_ctx.process->GetExitStatus();
+ const char *exit_description = exe_ctx.process->GetExitDescription();
+ strm.Printf ("Process %d exited with status = %i (0x%8.8x) %s\n",
+ exe_ctx.process->GetID(),
+ exit_status,
+ exit_status,
+ exit_description ? exit_description : "");
+ }
+ else
+ {
+ strm.Printf ("Process %d state is %s\n", exe_ctx.process->GetID(), StateAsCString (state));
+ if (exe_ctx.thread == NULL)
+ exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get();
+ if (exe_ctx.thread != NULL)
+ {
+ DisplayThreadsInfo (interpreter, &exe_ctx, result, false, false);
+ }
+ else
+ {
+ result.AppendError ("no valid thread found in current process");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("process is currently running");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no current location or status available");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordThread
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter *interpreter) :
+ CommandObjectMultiword ("thread",
+ "A set of commands for operating on one or more thread within a running process.",
+ "thread <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand (CommandObjectSP (new CommandObjectThreadBacktrace ()), "backtrace", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectThreadContinue ()), "continue", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectThreadList ()), "list", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectThreadSelect ()), "select", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectThreadUntil ()), "until", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-in",
+ "Source level single step in in specified thread (current thread, if none specified).",
+ "thread step-in [<thread-id>]",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
+ eStepTypeInto,
+ eStepScopeSource)),
+ "step-in", interpreter);
+
+ LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-out",
+ "Source level single step out in specified thread (current thread, if none specified).",
+ "thread step-out [<thread-id>]",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
+ eStepTypeOut,
+ eStepScopeSource)),
+ "step-out", interpreter);
+
+ LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-over",
+ "Source level single step over in specified thread (current thread, if none specified).",
+ "thread step-over [<thread-id>]",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
+ eStepTypeOver,
+ eStepScopeSource)),
+ "step-over", interpreter);
+
+ LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst",
+ "Single step one instruction in specified thread (current thread, if none specified).",
+ "thread step-inst [<thread-id>]",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
+ eStepTypeTrace,
+ eStepScopeInstruction)),
+ "step-inst", interpreter);
+ LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst-over",
+ "Single step one instruction in specified thread (current thread, if none specified), stepping over calls.",
+ "thread step-inst-over [<thread-id>]",
+ eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
+ eStepTypeTraceOver,
+ eStepScopeInstruction)),
+ "step-inst-over", interpreter);
+}
+
+CommandObjectMultiwordThread::~CommandObjectMultiwordThread ()
+{
+}
+
+
diff --git a/lldb/source/Commands/CommandObjectThread.h b/lldb/source/Commands/CommandObjectThread.h
new file mode 100644
index 00000000000..21bba714626
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectThread.h
@@ -0,0 +1,87 @@
+//===-- 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 CommandObjectThreadList : public CommandObject
+{
+public:
+
+ CommandObjectThreadList ();
+
+ ~CommandObjectThreadList ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+};
+
+
+class CommandObjectMultiwordThread : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordThread (CommandInterpreter *interpreter);
+
+ virtual
+ ~CommandObjectMultiwordThread ();
+
+};
+
+
+bool
+DisplayThreadInfo (CommandInterpreter *interpreter,
+ Stream &strm,
+ Thread *thread,
+ bool only_threads_with_stop_reason,
+ bool show_source);
+
+size_t
+DisplayThreadsInfo (CommandInterpreter *interpreter,
+ ExecutionContext *exe_ctx,
+ CommandReturnObject &result,
+ bool only_threads_with_stop_reason,
+ bool show_source);
+
+size_t
+DisplayFramesForExecutionContext (Thread *thread,
+ CommandInterpreter *interpreter,
+ Stream& strm,
+ bool ascending,
+ uint32_t first_frame,
+ uint32_t num_frames,
+ bool show_frame_info,
+ uint32_t num_frames_with_source,
+ uint32_t source_lines_before,
+ uint32_t source_lines_after);
+
+bool
+DisplayFrameForExecutionContext (Thread *thread,
+ StackFrame *frame,
+ CommandInterpreter *interpreter,
+ Stream& strm,
+ bool show_frame_info,
+ bool show_source,
+ uint32_t source_lines_before,
+ uint32_t source_lines_after);
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectThread_h_
diff --git a/lldb/source/Commands/CommandObjectTranslate.cpp b/lldb/source/Commands/CommandObjectTranslate.cpp
new file mode 100644
index 00000000000..48a10626c8d
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectTranslate.cpp
@@ -0,0 +1,75 @@
+//===-- CommandObjectTranslate.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectTranslate.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Options.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectTranslate
+//-------------------------------------------------------------------------
+
+CommandObjectTranslate::CommandObjectTranslate () :
+ CommandObject ("translate",
+ "Shows the actual function called for a given debugger command.",
+ "translate <command>")
+{
+}
+
+CommandObjectTranslate::~CommandObjectTranslate()
+{
+}
+
+
+bool
+CommandObjectTranslate::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ CommandObject *cmd_obj;
+
+ if (command.GetArgumentCount() != 0)
+ {
+ cmd_obj = interpreter->GetCommandObject(command.GetArgumentAtIndex(0));
+ if (cmd_obj)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ result.AppendMessageWithFormat ("%s\n", cmd_obj->Translate());
+ }
+ else
+ {
+ result.AppendErrroWithFormat
+ ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n",
+ command.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("must call translate with a valid command");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+}
diff --git a/lldb/source/Commands/CommandObjectTranslate.h b/lldb/source/Commands/CommandObjectTranslate.h
new file mode 100644
index 00000000000..efc3c8b4092
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectTranslate.h
@@ -0,0 +1,44 @@
+//===-- CommandObjectTranslate.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectTranslate_h_
+#define liblldb_CommandObjectTranslate_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectTranslate
+//-------------------------------------------------------------------------
+
+class CommandObjectTranslate : public CommandObject
+{
+public:
+
+ CommandObjectTranslate ();
+
+ virtual
+ ~CommandObjectTranslate ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectTranslate_h_
diff --git a/lldb/source/Commands/CommandObjectUnalias.cpp b/lldb/source/Commands/CommandObjectUnalias.cpp
new file mode 100644
index 00000000000..6c2f5085cf8
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectUnalias.cpp
@@ -0,0 +1,87 @@
+//===-- CommandObjectUnalias.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectUnalias.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;
+
+//-------------------------------------------------------------------------
+// CommandObjectUnalias
+//-------------------------------------------------------------------------
+
+CommandObjectUnalias::CommandObjectUnalias () :
+ CommandObject ("unalias",
+ "Allows the user to remove/delete a user-defined command abbreviation.",
+ "unalias <alias-name-to-be-removed>")
+{
+}
+
+CommandObjectUnalias::~CommandObjectUnalias()
+{
+}
+
+
+bool
+CommandObjectUnalias::Execute (Args& args, CommandContext *context, CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+{
+ CommandObject::CommandMap::iterator pos;
+ CommandObject *cmd_obj;
+
+ if (args.GetArgumentCount() != 0)
+ {
+ const char *command_name = args.GetArgumentAtIndex(0);
+ cmd_obj = interpreter->GetCommandObject(command_name);
+ if (cmd_obj)
+ {
+ if (interpreter->CommandExists (command_name))
+ {
+ result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
+ command_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+
+ if (interpreter->RemoveAlias (command_name) == false)
+ {
+ if (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();
+}
+
diff --git a/lldb/source/Commands/CommandObjectUnalias.h b/lldb/source/Commands/CommandObjectUnalias.h
new file mode 100644
index 00000000000..5d1cafbcc71
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectUnalias.h
@@ -0,0 +1,44 @@
+//===-- CommandObjectUnalias.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectUnalias_h_
+#define liblldb_CommandObjectUnalias_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectUnalias
+//-------------------------------------------------------------------------
+
+class CommandObjectUnalias : public CommandObject
+{
+public:
+
+ CommandObjectUnalias ();
+
+ virtual
+ ~CommandObjectUnalias ();
+
+ virtual bool
+ Execute (Args& args,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectUnalias_h_
diff --git a/lldb/source/Commands/CommandObjectVariable.cpp b/lldb/source/Commands/CommandObjectVariable.cpp
new file mode 100644
index 00000000000..6bde4829be0
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectVariable.cpp
@@ -0,0 +1,801 @@
+//===-- CommandObjectVariable.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectVariable.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Options.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectVariable.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.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/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//void
+//DumpValueObjectValues (Stream *sout, const char *root_valobj_name, ValueObjectSP& valobj_sp, bool follow_ptrs_and_refs, uint32_t curr_depth, uint32_t max_depth)
+//{
+// ValueObject *valobj = valobj_sp.get();
+// if (valobj)
+// {
+// const char *name_cstr = valobj->GetName().AsCString(NULL);
+// const char *val_cstr = valobj->GetValueAsCString();
+// const char *loc_cstr = valobj->GetLocationAsCString();
+// const char *type_cstr = valobj->GetTypeName().AsCString();
+// const char *sum_cstr = valobj->GetSummaryAsCString();
+// const char *err_cstr = valobj->GetError().AsCString();
+// // Indent
+// sout->Indent();
+// if (root_valobj_name)
+// {
+// sout->Printf ("%s = ", root_valobj_name);
+// }
+//
+// if (name_cstr)
+// sout->Printf ("%s => ", name_cstr);
+//
+// sout->Printf ("ValueObject{%u}", valobj->GetID());
+// const uint32_t num_children = valobj->GetNumChildren();
+//
+// if (type_cstr)
+// sout->Printf (", type = '%s'", type_cstr);
+//
+// if (loc_cstr)
+// sout->Printf (", location = %s", loc_cstr);
+//
+// sout->Printf (", num_children = %u", num_children);
+//
+// if (val_cstr)
+// sout->Printf (", value = %s", val_cstr);
+//
+// if (err_cstr)
+// sout->Printf (", error = %s", err_cstr);
+//
+// if (sum_cstr)
+// sout->Printf (", summary = %s", sum_cstr);
+//
+// sout->EOL();
+// bool is_ptr_or_ref = ClangASTContext::IsPointerOrReferenceType (valobj->GetOpaqueClangQualType());
+// if (!follow_ptrs_and_refs && is_ptr_or_ref)
+// return;
+//
+// if (curr_depth < max_depth)
+// {
+// for (uint32_t idx=0; idx<num_children; ++idx)
+// {
+// ValueObjectSP child_sp(valobj->GetChildAtIndex(idx, true));
+// if (child_sp.get())
+// {
+// sout->IndentMore();
+// DumpValueObjectValues (sout, NULL, child_sp, follow_ptrs_and_refs, curr_depth + 1, max_depth);
+// sout->IndentLess();
+// }
+// }
+// }
+// }
+//}
+
+//----------------------------------------------------------------------
+// List images with associated information
+//----------------------------------------------------------------------
+class CommandObjectVariableList : public CommandObject
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions () :
+ Options()
+ {
+ ResetOptionValues ();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (int option_idx, const char *option_arg)
+ {
+ Error error;
+ bool success;
+ char short_option = (char) m_getopt_table[option_idx].val;
+ switch (short_option)
+ {
+ case 'o': use_objc = true; break;
+ case 'n': name = option_arg; break;
+ case 'r': use_regex = true; break;
+ case 'a': show_args = false; break;
+ case 'l': show_locals = false; break;
+ case 'g': show_globals = false; break;
+ case 't': show_types = false; break;
+ case 'y': show_summary = false; break;
+ case 'L': show_location= true; break;
+ case 'D': debug = true; break;
+ case 'd':
+ max_depth = Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("Invalid max depth '%s'.\n", option_arg);
+ break;
+
+ case 'p':
+ ptr_depth = Args::StringToUInt32 (option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("Invalid pointer depth '%s'.\n", option_arg);
+ break;
+
+ case 'G':
+ {
+ ConstString const_string (option_arg);
+ globals.push_back(const_string);
+ }
+ break;
+
+ case 's':
+ show_scope = true;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ ResetOptionValues ()
+ {
+ Options::ResetOptionValues();
+
+ name.clear();
+ use_objc = false;
+ use_regex = false;
+ show_args = true;
+ show_locals = true;
+ show_globals = true;
+ show_types = true;
+ show_scope = false;
+ show_summary = true;
+ show_location = false;
+ debug = false;
+ max_depth = UINT32_MAX;
+ ptr_depth = 0;
+ globals.clear();
+ }
+
+ const lldb::OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb::OptionDefinition g_option_table[];
+ std::string name;
+ bool use_objc;
+ bool use_regex;
+ bool show_args;
+ bool show_locals;
+ bool show_globals;
+ bool show_types;
+ bool show_scope; // local/arg/global/static
+ bool show_summary;
+ bool show_location;
+ bool debug;
+ uint32_t max_depth; // The depth to print when dumping concrete (not pointers) aggreate values
+ uint32_t ptr_depth; // The default depth that is dumped when we find pointers
+ std::vector<ConstString> globals;
+ // Instance variables to hold the values for command options.
+ };
+
+ CommandObjectVariableList () :
+ CommandObject (
+ "variable list",
+ "Show specified argument, local variable, static variable or global variable. If none specified, list them all.",
+ "variable list [<cmd-options>] [<var-name1> [<var-name2>...]]")
+ {
+ }
+
+ virtual
+ ~CommandObjectVariableList ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ void
+ DumpVariable (CommandReturnObject &result, ExecutionContext *exe_ctx, Variable *variable)
+ {
+ if (variable)
+ {
+ Stream &s = result.GetOutputStream();
+ DWARFExpression &expr = variable->LocationExpression();
+ Value expr_result;
+ Error expr_error;
+ Type *variable_type = variable->GetType();
+ bool expr_success = expr.Evaluate(exe_ctx, NULL, NULL, expr_result, &expr_error);
+
+ if (m_options.debug)
+ s.Printf ("Variable{0x%8.8x}: ", variable->GetID());
+
+ if (!expr_success)
+ s.Printf ("%s = ERROR (%s)", variable->GetName().AsCString(NULL), expr_error.AsCString());
+ else
+ {
+ Value::ValueType expr_value_type = expr_result.GetValueType();
+ switch (expr_value_type)
+ {
+ case Value::eValueTypeScalar:
+ s.Printf ("%s = ", variable->GetName().AsCString(NULL));
+ if (variable_type)
+ {
+ DataExtractor data;
+ if (expr_result.ResolveValue (exe_ctx, NULL).GetData (data))
+ variable_type->DumpValue (exe_ctx, &s, data, 0, m_options.show_types, m_options.show_summary, m_options.debug);
+ }
+ break;
+
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeHostAddress:
+ {
+ s.Printf ("%s = ", variable->GetName().AsCString(NULL));
+ lldb::addr_t addr = LLDB_INVALID_ADDRESS;
+ lldb::AddressType addr_type = eAddressTypeLoad;
+
+ if (expr_value_type == Value::eValueTypeFileAddress)
+ {
+ lldb::addr_t file_addr = expr_result.ResolveValue (exe_ctx, NULL).ULongLong(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());
+ addr = so_addr.GetLoadAddress(exe_ctx->process);
+ }
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ result.GetErrorStream().Printf ("error: %s is not loaded", var_sc.module_sp->GetFileSpec().GetFilename().AsCString());
+ }
+ }
+ else
+ {
+ result.GetErrorStream().Printf ("error: unable to resolve the variable address 0x%llx", file_addr);
+ }
+ }
+ else
+ {
+ if (expr_value_type == Value::eValueTypeHostAddress)
+ addr_type = eAddressTypeHost;
+ addr = expr_result.ResolveValue (exe_ctx, NULL).ULongLong(LLDB_INVALID_ADDRESS);
+ }
+
+ if (addr != LLDB_INVALID_ADDRESS)
+ {
+ if (m_options.debug)
+ s.Printf("@ 0x%8.8llx, value = ", addr);
+ variable_type->DumpValueInMemory (exe_ctx, &s, addr, addr_type, m_options.show_types, m_options.show_summary, m_options.debug);
+ }
+ }
+ break;
+ }
+ }
+ s.EOL();
+ }
+ }
+
+ void
+ DumpValueObject (CommandReturnObject &result,
+ ExecutionContextScope *exe_scope,
+ ValueObject *valobj,
+ const char *root_valobj_name,
+ uint32_t ptr_depth,
+ uint32_t curr_depth,
+ uint32_t max_depth,
+ bool use_objc)
+ {
+ if (valobj)
+ {
+ Stream &s = result.GetOutputStream();
+
+ //const char *loc_cstr = valobj->GetLocationAsCString();
+ if (m_options.show_location)
+ {
+ s.Printf("@ %s: ", valobj->GetLocationAsCString(exe_scope));
+ }
+ if (m_options.debug)
+ s.Printf ("%p ValueObject{%u} ", valobj, valobj->GetID());
+
+ s.Indent();
+
+ if (m_options.show_types)
+ s.Printf("(%s) ", valobj->GetTypeName().AsCString());
+
+ const char *name_cstr = root_valobj_name ? root_valobj_name : valobj->GetName().AsCString("");
+ s.Printf ("%s = ", name_cstr);
+
+ const char *val_cstr = valobj->GetValueAsCString(exe_scope);
+ const char *err_cstr = valobj->GetError().AsCString();
+
+ if (err_cstr)
+ {
+ s.Printf ("error: %s\n", err_cstr);
+ }
+ else
+ {
+ const char *sum_cstr = valobj->GetSummaryAsCString(exe_scope);
+
+ const bool is_aggregate = ClangASTContext::IsAggregateType (valobj->GetOpaqueClangQualType());
+
+ if (val_cstr)
+ s.PutCString(val_cstr);
+
+ if (sum_cstr)
+ s.Printf(" %s", sum_cstr);
+
+ if (use_objc)
+ {
+ if (!ClangASTContext::IsPointerType (valobj->GetOpaqueClangQualType()))
+ return;
+
+ if (!valobj->GetValueIsValid())
+ return;
+
+ Process *process = exe_scope->CalculateProcess();
+
+ if (!process)
+ return;
+
+ Scalar scalar;
+
+ if (!Type::GetValueAsScalar (valobj->GetClangAST(),
+ valobj->GetOpaqueClangQualType(),
+ valobj->GetDataExtractor(),
+ 0,
+ valobj->GetByteSize(),
+ scalar))
+ return;
+
+ ConstString po_output;
+
+ ExecutionContext exe_ctx;
+ exe_scope->Calculate(exe_ctx);
+
+ Value val(scalar);
+ val.SetContext(Value::eContextTypeOpaqueClangQualType,
+ ClangASTContext::GetVoidPtrType(valobj->GetClangAST(), false));
+
+ if (!process->GetObjCObjectPrinter().PrintObject(po_output, val, exe_ctx))
+ return;
+
+ s.Printf("\n%s\n", po_output.GetCString());
+
+ return;
+ }
+
+
+ if (curr_depth < max_depth)
+ {
+ if (is_aggregate)
+ s.PutChar('{');
+
+ bool is_ptr_or_ref = ClangASTContext::IsPointerOrReferenceType (valobj->GetOpaqueClangQualType());
+
+ if (is_ptr_or_ref && ptr_depth == 0)
+ return;
+
+ const uint32_t num_children = valobj->GetNumChildren();
+ if (num_children)
+ {
+ s.IndentMore();
+ for (uint32_t idx=0; idx<num_children; ++idx)
+ {
+ ValueObjectSP child_sp(valobj->GetChildAtIndex(idx, true));
+ if (child_sp.get())
+ {
+ s.EOL();
+ DumpValueObject (result,
+ exe_scope,
+ child_sp.get(),
+ NULL,
+ is_ptr_or_ref ? ptr_depth - 1 : ptr_depth,
+ curr_depth + 1,
+ max_depth,
+ false);
+ if (idx + 1 < num_children)
+ s.PutChar(',');
+ }
+ }
+ s.IndentLess();
+ }
+ if (is_aggregate)
+ {
+ s.EOL();
+ s.Indent("}");
+ }
+ }
+ else
+ {
+ if (is_aggregate)
+ {
+ s.PutCString("{...}");
+ }
+ }
+
+ }
+ }
+ }
+
+ virtual bool
+ Execute (Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result)
+ {
+ ExecutionContext exe_ctx(context->GetExecutionContext());
+ if (exe_ctx.frame == NULL)
+ {
+ result.AppendError ("invalid frame");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ VariableList variable_list;
+
+ SymbolContext frame_sc = exe_ctx.frame->GetSymbolContext (eSymbolContextEverything);
+ if (exe_ctx.frame && frame_sc.block)
+ frame_sc.block->AppendVariables(true, true, &variable_list);
+ VariableSP var_sp;
+ ValueObjectSP valobj_sp;
+ //ValueObjectList &valobj_list = exe_ctx.frame->GetValueObjectList();
+ const char *name_cstr = NULL;
+ size_t idx;
+ if (!m_options.globals.empty())
+ {
+ uint32_t fail_count = 0;
+ Target *target = context->GetTarget();
+ if (target)
+ {
+ const size_t num_globals = m_options.globals.size();
+ for (idx = 0; idx < num_globals; ++idx)
+ {
+ VariableList global_var_list;
+ const uint32_t num_matching_globals = target->GetImages().FindGlobalVariables (m_options.globals[idx], true, UINT32_MAX, global_var_list);
+
+ if (num_matching_globals == 0)
+ {
+ ++fail_count;
+ result.GetErrorStream().Printf ("error: can't find global variable '%s'\n", m_options.globals[idx].AsCString());
+ }
+ else
+ {
+ for (uint32_t global_idx=0; global_idx<num_matching_globals; ++global_idx)
+ {
+ var_sp = global_var_list.GetVariableAtIndex(global_idx);
+ if (var_sp)
+ {
+ valobj_sp = exe_ctx.frame->GetValueObjectList().FindValueObjectByValueName (m_options.globals[idx].AsCString());
+ if (!valobj_sp)
+ valobj_sp.reset (new ValueObjectVariable (var_sp));
+
+ if (valobj_sp)
+ {
+ exe_ctx.frame->GetValueObjectList().Append (valobj_sp);
+ DumpValueObject (result, exe_ctx.frame, valobj_sp.get(), name_cstr, m_options.ptr_depth, 0, m_options.max_depth, false);
+ result.GetOutputStream().EOL();
+ }
+ }
+ }
+ }
+ }
+ }
+ if (fail_count)
+ {
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+
+ if (command.GetArgumentCount() > 0)
+ {
+ // 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)
+ {
+ uint32_t ptr_depth = m_options.ptr_depth;
+ // If first character is a '*', then show pointer contents
+ if (name_cstr[0] == '*')
+ {
+ ++ptr_depth;
+ name_cstr++; // Skip the '*'
+ }
+
+ std::string var_path (name_cstr);
+ size_t separator_idx = var_path.find_first_of(".-[");
+
+ 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);
+ if (var_sp)
+ {
+ //DumpVariable (result, &exe_ctx, var_sp.get());
+ // TODO: redo history variables using a different map
+// if (var_path[0] == '$')
+// valobj_sp = valobj_list.FindValueObjectByValueObjectName (name_const_string.GetCString());
+// else
+ valobj_sp = exe_ctx.frame->GetValueObjectList().FindValueObjectByValueName (name_const_string.GetCString());
+
+ if (!valobj_sp)
+ {
+ valobj_sp.reset (new ValueObjectVariable (var_sp));
+ exe_ctx.frame->GetValueObjectList().Append (valobj_sp);
+ }
+
+ var_path.erase (0, name_const_string.GetLength ());
+ // 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] != '>')
+ {
+ result.GetErrorStream().Printf ("error: invalid character in variable path starting at '%s'\n",
+ var_path.c_str());
+ var_path.clear();
+ valobj_sp.reset();
+ break;
+ }
+ var_path.erase (0, 1); // Remove the '-'
+ // Fall through
+ case '.':
+ {
+ 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);
+
+ child_valobj_sp = valobj_sp->GetChildMemberWithName (child_name, true);
+ if (!child_valobj_sp)
+ {
+ result.GetErrorStream().Printf ("error: can't find child of '%s' named '%s'\n",
+ valobj_sp->GetName().AsCString(),
+ child_name.GetCString());
+ var_path.clear();
+ valobj_sp.reset();
+ break;
+ }
+ // Remove the child name from the path
+ var_path.erase(0, child_name.GetLength());
+ }
+ 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;
+ int32_t child_index = ::strtol (&var_path[1], &end, 0);
+ if (end && *end == ']')
+ {
+
+ if (valobj_sp->IsPointerType ())
+ {
+ child_valobj_sp = valobj_sp->GetSyntheticArrayMemberFromPointer (child_index, true);
+ }
+ else
+ {
+ child_valobj_sp = valobj_sp->GetChildAtIndex (child_index, true);
+ }
+
+ if (!child_valobj_sp)
+ {
+ result.GetErrorStream().Printf ("error: invalid array index %u in '%s'\n",
+ child_index,
+ valobj_sp->GetName().AsCString());
+ var_path.clear();
+ valobj_sp.reset();
+ break;
+ }
+
+ // 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(".-[");
+
+ // Break out early from the switch since we were able to find the child member
+ break;
+ }
+ }
+ result.GetErrorStream().Printf ("error: invalid array member specification for '%s' starting at '%s'\n",
+ valobj_sp->GetName().AsCString(),
+ var_path.c_str());
+ var_path.clear();
+ valobj_sp.reset();
+ break;
+
+ break;
+
+ default:
+ result.GetErrorStream().Printf ("error: invalid character in variable path starting at '%s'\n",
+ var_path.c_str());
+ var_path.clear();
+ valobj_sp.reset();
+ separator_idx = std::string::npos;
+ break;
+ }
+
+ if (child_valobj_sp)
+ valobj_sp = child_valobj_sp;
+
+ if (var_path.empty())
+ break;
+
+ }
+
+ if (valobj_sp)
+ {
+ DumpValueObject (result, exe_ctx.frame, valobj_sp.get(), name_cstr, ptr_depth, 0, m_options.max_depth, m_options.use_objc);
+ result.GetOutputStream().EOL();
+ }
+ }
+ else
+ {
+ result.GetErrorStream().Printf ("error: unable to find any variables named '%s'\n", name_cstr);
+ var_path.clear();
+ }
+ }
+ }
+ else
+ {
+
+ if (m_options.show_globals)
+ {
+ if (frame_sc.comp_unit)
+ {
+ variable_list.AddVariables (frame_sc.comp_unit->GetVariableList(true).get());
+ }
+ }
+
+ const uint32_t num_variables = variable_list.GetSize();
+
+ if (num_variables > 0)
+ {
+ for (uint32_t i=0; i<num_variables; i++)
+ {
+ Variable *variable = variable_list.GetVariableAtIndex(i).get();
+ bool dump_variable = true;
+
+ switch (variable->GetScope())
+ {
+ case eValueTypeVariableGlobal:
+ dump_variable = m_options.show_globals;
+ if (dump_variable && m_options.show_scope)
+ result.GetOutputStream().PutCString("GLOBAL: ");
+ break;
+
+ case eValueTypeVariableStatic:
+ dump_variable = m_options.show_globals;
+ if (dump_variable && m_options.show_scope)
+ result.GetOutputStream().PutCString("STATIC: ");
+ break;
+
+ case eValueTypeVariableArgument:
+ dump_variable = m_options.show_args;
+ if (dump_variable && m_options.show_scope)
+ result.GetOutputStream().PutCString(" ARG: ");
+ break;
+
+ case eValueTypeVariableLocal:
+ dump_variable = m_options.show_locals;
+ if (dump_variable && m_options.show_scope)
+ result.GetOutputStream().PutCString(" LOCAL: ");
+ break;
+
+ default:
+ break;
+ }
+
+ if (dump_variable)
+ DumpVariable (result, &exe_ctx, variable);
+ }
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ return result.Succeeded();
+ }
+protected:
+
+ CommandOptions m_options;
+};
+
+lldb::OptionDefinition
+CommandObjectVariableList::CommandOptions::g_option_table[] =
+{
+{ 0, false, "debug", 'D', no_argument, NULL, 0, NULL, "Show verbose debug information."},
+{ 0, false, "depth", 'd', required_argument, NULL, 0, "<count>", "Set the max recurse depth when dumping aggregate types (default is infinity)."},
+{ 0, false, "globals", 'g', no_argument, NULL, 0, NULL, "List global and static variables for the current stack frame source file."},
+{ 0, false, "global", 'G', required_argument, NULL, 0, NULL, "Find a global variable by name (which might not be in the current stack frame source file)."},
+{ 0, false, "location", 'L', no_argument, NULL, 0, NULL, "Show variable location information."},
+{ 0, false, "name", 'n', required_argument, NULL, 0, "<name>", "Lookup a variable by name or regex (--regex) for the current execution context."},
+{ 0, false, "no-args", 'a', no_argument, NULL, 0, NULL, "Omit function arguments."},
+{ 0, false, "no-locals", 'l', no_argument, NULL, 0, NULL, "Omit local variables."},
+{ 0, false, "no-types", 't', no_argument, NULL, 0, NULL, "Omit variable type names."},
+{ 0, false, "no-summary", 'y', no_argument, NULL, 0, NULL, "Omit summary information."},
+{ 0, false, "scope", 's', no_argument, NULL, 0, NULL, "Show variable scope (argument, local, global, static)."},
+{ 0, false, "objc", 'o', no_argument, NULL, 0, NULL, "When looking up a variable by name (--name), print as an Objective-C object."},
+{ 0, false, "ptr-depth", 'p', required_argument, NULL, 0, "<count>", "The number of pointers to be traversed when dumping values (default is zero)."},
+{ 0, false, "regex", 'r', no_argument, NULL, 0, NULL, "The <name> argument for name lookups are regular expressions."},
+{ 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
+};
+
+//----------------------------------------------------------------------
+// CommandObjectVariable constructor
+//----------------------------------------------------------------------
+CommandObjectVariable::CommandObjectVariable(CommandInterpreter *interpreter) :
+ CommandObjectMultiword ("variable",
+ "Access program arguments, locals, static and global variables.",
+ "variable [list] ...")
+{
+ LoadSubCommand (CommandObjectSP (new CommandObjectVariableList ()), "list", interpreter);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommandObjectVariable::~CommandObjectVariable()
+{
+}
+
+
+
+
diff --git a/lldb/source/Commands/CommandObjectVariable.h b/lldb/source/Commands/CommandObjectVariable.h
new file mode 100644
index 00000000000..65869c73d72
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectVariable.h
@@ -0,0 +1,43 @@
+//===-- CommandObjectVariable.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandObjectVariable_h_
+#define liblldb_CommandObjectVariable_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectImage
+//-------------------------------------------------------------------------
+
+class CommandObjectVariable : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectVariable (CommandInterpreter *iterpreter);
+
+ virtual
+ ~CommandObjectVariable ();
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectVariable only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectVariable);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectVariable_h_
diff --git a/lldb/source/Core/Address.cpp b/lldb/source/Core/Address.cpp
new file mode 100644
index 00000000000..e2481e133fa
--- /dev/null
+++ b/lldb/source/Core/Address.cpp
@@ -0,0 +1,875 @@
+//===-- 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/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.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;
+
+ lldb::AddressType addr_type = eAddressTypeInvalid;
+ addr_t addr = LLDB_INVALID_ADDRESS;
+
+ Process *process = exe_scope->CalculateProcess();
+
+ if (process && process->IsAlive())
+ {
+ addr = address.GetLoadAddress(process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ addr_type = eAddressTypeLoad;
+ }
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ addr = address.GetFileAddress();
+ if (addr != LLDB_INVALID_ADDRESS)
+ addr_type = eAddressTypeFile;
+ }
+
+ if (addr_type == eAddressTypeInvalid)
+ return false;
+
+ Target *target = exe_scope->CalculateTarget();
+ if (target)
+ {
+ Error error;
+ return target->ReadMemory (addr_type, addr, dst, dst_len, error, NULL);
+ }
+ 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;
+
+ Process *process = exe_scope->CalculateProcess();
+ if (process)
+ {
+ byte_order = process->GetByteOrder();
+ addr_size = process->GetAddressByteSize();
+ }
+
+ if (byte_order == eByteOrderInvalid || addr_size == 0)
+ {
+ Module *module = address.GetModule();
+ if (module)
+ {
+ byte_order = module->GetArchitecture().GetDefaultEndian();
+ addr_size = module->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;
+
+ 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);
+ uint32_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)
+ {
+ Process *process = exe_scope->CalculateProcess();
+ if (process && process->IsAlive())
+ {
+ if (!process->ResolveLoadAddress (deref_addr, deref_so_addr))
+ {
+ deref_so_addr.SetSection(NULL);
+ deref_so_addr.SetOffset(deref_addr);
+ }
+ }
+ else
+ {
+ Target *target = exe_scope->CalculateTarget();
+ if (target == NULL)
+ return false;
+
+ if (!target->GetImages().ResolveFileAddress(deref_addr, deref_so_addr))
+ {
+ deref_so_addr.SetSection(NULL);
+ deref_so_addr.SetOffset(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)
+ 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.data(), 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 adderss size don't matter for C string dumping..
+ DataExtractor data (buf, sizeof(buf), eByteOrderHost, 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 () :
+ m_section (NULL),
+ m_offset (LLDB_INVALID_ADDRESS)
+{
+}
+
+Address::Address (const Address& rhs) :
+ m_section (rhs.m_section),
+ m_offset (rhs.m_offset)
+{
+}
+
+Address::Address (const Section* section, addr_t offset) :
+ m_section (section),
+ m_offset (offset)
+{
+}
+
+Address::Address (addr_t address, const SectionList * sections) :
+ m_section (NULL),
+ m_offset (LLDB_INVALID_ADDRESS)
+{
+ ResolveAddressUsingFileSections(address, sections);
+}
+
+Address::~Address ()
+{
+}
+
+
+const Address&
+Address::operator= (const Address& rhs)
+{
+ if (this != &rhs)
+ {
+ m_section = rhs.m_section;
+ m_offset = rhs.m_offset;
+ }
+ return *this;
+}
+
+bool
+Address::IsValid() const
+{
+ return m_offset != LLDB_INVALID_ADDRESS;
+}
+
+bool
+Address::IsSectionOffset() const
+{
+ return m_section != NULL && IsValid();
+}
+
+bool
+Address::ResolveAddressUsingFileSections (addr_t addr, const SectionList *sections)
+{
+ if (sections)
+ m_section = sections->FindSectionContainingFileAddress(addr).get();
+ else
+ m_section = NULL;
+
+ if (m_section != NULL)
+ {
+ assert( m_section->ContainsFileAddress(addr) );
+ m_offset = addr - m_section->GetFileAddress();
+ return true; // Successfully transformed addr into a section offset address
+ }
+
+ m_offset = addr;
+ return false; // Failed to resolve this address to a section offset value
+}
+
+//bool
+//Address::ResolveAddressUsingLoadSections (addr_t addr, const SectionList *sections)
+//{
+// if (sections)
+// m_section = sections->FindSectionContainingLoadAddress(addr).get();
+// else
+// m_section = NULL;
+//
+// if (m_section != NULL)
+// {
+// assert( m_section->ContainsLoadAddress(addr) );
+// m_offset = addr - m_section->GetLoadBaseAddress();
+// return true; // Successfully transformed addr into a section offset address
+// }
+//
+// m_offset = addr;
+// return false; // Failed to resolve this address to a section offset value
+//}
+//
+Module *
+Address::GetModule () const
+{
+ if (m_section)
+ return m_section->GetModule();
+ return NULL;
+}
+
+const Section*
+Address::GetSection () const
+{
+ return m_section;
+}
+
+
+//addr_t
+//Address::Address() const
+//{
+// addr_t addr = GetLoadAddress();
+// if (addr != LLDB_INVALID_ADDRESS)
+// return addr;
+// return GetFileAddress();
+//}
+//
+
+addr_t
+Address::GetFileAddress () const
+{
+ if (m_section != NULL)
+ {
+ addr_t sect_file_addr = m_section->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 (Process *process) const
+{
+ if (m_section != NULL)
+ {
+ if (process)
+ {
+ addr_t sect_load_addr = m_section->GetLoadBaseAddress (process);
+
+ 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;
+ }
+ // No section, we just return the offset since it is the value in this case
+ return m_offset;
+}
+
+addr_t
+Address::GetOffset () const
+{
+ return m_offset;
+}
+
+bool
+Address::SetOffset (addr_t offset)
+{
+ bool changed = m_offset != offset;
+ m_offset = offset;
+ return changed;
+}
+
+void
+Address::SetSection (const Section* section)
+{
+ m_section = section;
+}
+
+void
+Address::Clear()
+{
+ m_section = NULL;
+ m_offset = LLDB_INVALID_ADDRESS;
+}
+
+
+bool
+Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style) const
+{
+ // If the section was NULL, only load address is going to work.
+ if (m_section == NULL)
+ style = DumpStyleLoadAddress;
+
+ Process *process = NULL;
+ if (exe_scope)
+ process = exe_scope->CalculateProcess();
+ int addr_size = sizeof (addr_t);
+ if (process)
+ addr_size = process->GetAddressByteSize ();
+
+ lldb_private::Address so_addr;
+
+ switch (style)
+ {
+ case DumpStyleSectionNameOffset:
+ if (m_section != NULL)
+ {
+ m_section->DumpName(s);
+ s->Printf (" + %llu", m_offset);
+ }
+ else
+ {
+ s->Printf("0x%16.16llx", m_offset);
+ }
+ break;
+
+ case DumpStyleSectionPointerOffset:
+ s->Printf("(Section *)%.*p + 0x%16.16llx", (int)sizeof(void*) * 2, m_section, m_offset);
+ break;
+
+ case DumpStyleModuleWithFileAddress:
+ s->Printf("%s[", m_section->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);
+ return false;
+ }
+ s->Address (file_addr, addr_size);
+ if (style == DumpStyleModuleWithFileAddress)
+ s->PutChar(']');
+ }
+ break;
+
+ case DumpStyleLoadAddress:
+ {
+ addr_t load_addr = GetLoadAddress (process);
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style);
+ return false;
+ }
+ s->Address (load_addr, addr_size);
+ }
+ break;
+
+ case DumpStyleResolvedDescription:
+ if (IsSectionOffset())
+ {
+ lldb::AddressType addr_type = eAddressTypeLoad;
+ addr_t addr = GetLoadAddress (process);
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ addr = GetFileAddress();
+ addr_type = eAddressTypeFile;
+ }
+
+ uint32_t pointer_size = 4;
+ lldb_private::Module *module = GetModule();
+ if (process)
+ pointer_size = process->GetAddressByteSize();
+ else if (module)
+ pointer_size = module->GetArchitecture().GetAddressByteSize();
+
+ bool showed_info = false;
+ const Section *section = GetSection();
+ if (section)
+ {
+ SectionType sect_type = section->GetSectionType();
+ switch (sect_type)
+ {
+ 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 (so_addr.IsSectionOffset())
+ {
+ lldb_private::SymbolContext func_sc;
+ process->GetTarget().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, process, so_addr, true);
+ 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())
+ {
+ lldb_private::SymbolContext pointer_sc;
+ process->GetTarget().GetImages().ResolveSymbolContextForAddress (so_addr,
+ eSymbolContextEverything,
+ pointer_sc);
+ if (pointer_sc.function || pointer_sc.symbol)
+ {
+ s->PutCString(": ");
+ pointer_sc.DumpStopContext(s, process, so_addr, false);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (!showed_info)
+ {
+ if (module)
+ {
+ lldb_private::SymbolContext sc;
+ module->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc);
+ if (sc.function || sc.symbol)
+ {
+ bool show_stop_context = 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->GetAddressRangePtr())
+ {
+ if (sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetSection() != GetSection())
+ 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, process, *this, false);
+ }
+ 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);
+ return false;
+ }
+ break;
+ }
+
+ return true;
+}
+
+//Stream& operator << (Stream& s, const Address& so_addr)
+//{
+// so_addr.Dump(&s, Address::DumpStyleSectionNameOffset);
+// return s;
+//}
+//
+void
+Address::CalculateSymbolContext (SymbolContext *sc)
+{
+ sc->Clear();
+ // Absolute addresses don't have enough information to reconstruct even their target.
+ if (m_section == NULL)
+ return;
+
+ if (m_section->GetModule())
+ {
+ sc->module_sp = m_section->GetModule()->GetSP();
+ if (sc->module_sp)
+ sc->module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextEverything, *sc);
+ }
+}
+
+void
+Address::DumpSymbolContext (Stream *s)
+{
+ SymbolContext sc;
+ CalculateSymbolContext (&sc);
+ sc.Dump (s, NULL);
+}
+
+void
+Address::DumpDebug(Stream *s) const
+{
+ *s << (void *)this << ": " << "Address";
+ if (m_section != NULL)
+ {
+ *s << ", section = " << (void *)m_section << " (" << m_section->GetName() << "), offset = " << m_offset;
+ }
+ else
+ {
+ *s << ", vm_addr = " << m_offset;
+ }
+ s->EOL();
+}
+
+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, Process *process)
+{
+ assert (process != NULL);
+ addr_t a_load_addr = a.GetLoadAddress (process);
+ addr_t b_load_addr = b.GetLoadAddress (process);
+ 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)
+{
+ Module *a_module = a.GetModule ();
+ Module *b_module = b.GetModule ();
+ 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);
+}
+
+
+/// The only comparisons that make sense are the load addresses
+//bool
+//lldb::operator< (const Address& lhs, const Address& rhs)
+//{
+// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
+// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
+//
+// if (lhs_addr == rhs_addr)
+// {
+// lhs_addr = lhs.GetFileAddress();
+// rhs_addr = rhs.GetFileAddress();
+// }
+// return lhs_addr < rhs_addr;
+//}
+//
+//bool
+//lldb::operator<= (const Address& lhs, const Address& rhs)
+//{
+// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
+// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
+//
+// if (lhs_addr == rhs_addr)
+// {
+// lhs_addr = lhs.GetFileAddress();
+// rhs_addr = rhs.GetFileAddress();
+// }
+// return lhs_addr <= rhs_addr;
+//}
+//
+//bool
+//lldb::operator> (const Address& lhs, const Address& rhs)
+//{
+// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
+// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
+//
+// if (lhs_addr == rhs_addr)
+// {
+// lhs_addr = lhs.GetFileAddress();
+// rhs_addr = rhs.GetFileAddress();
+// }
+// return lhs_addr > rhs_addr;
+//}
+//
+//bool
+//lldb::operator>= (const Address& lhs, const Address& rhs)
+//{
+// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
+// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
+//
+// if (lhs_addr == rhs_addr)
+// {
+// lhs_addr = lhs.GetFileAddress();
+// rhs_addr = rhs.GetFileAddress();
+// }
+// return lhs_addr >= rhs_addr;
+//}
+//
+
+// The operator == checks for exact equality only (same section, same offset)
+bool
+lldb_private::operator== (const Address& a, const Address& rhs)
+{
+ return a.GetSection() == rhs.GetSection() &&
+ a.GetOffset() == rhs.GetOffset();
+}
+// The operator != checks for exact inequality only (differing section, or
+// different offset)
+bool
+lldb_private::operator!= (const Address& a, const Address& rhs)
+{
+ return a.GetSection() != rhs.GetSection() ||
+ a.GetOffset() != rhs.GetOffset();
+}
+
+bool
+Address::IsLinkedAddress () const
+{
+ return m_section && m_section->GetLinkedSection();
+}
+
+
+void
+Address::ResolveLinkedAddress ()
+{
+ if (m_section)
+ {
+ const Section *linked_section = m_section->GetLinkedSection();
+ if (linked_section)
+ {
+ m_offset += m_section->GetLinkedOffset();
+ m_section = linked_section;
+ }
+ }
+}
diff --git a/lldb/source/Core/AddressRange.cpp b/lldb/source/Core/AddressRange.cpp
new file mode 100644
index 00000000000..8c2997936fd
--- /dev/null
+++ b/lldb/source/Core/AddressRange.cpp
@@ -0,0 +1,222 @@
+//===-- 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/Stream.h"
+#include "lldb/Target/Process.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 Section* 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 ()
+{
+}
+
+Address &
+AddressRange::GetBaseAddress()
+{
+ return m_base_addr;
+}
+
+const Address &
+AddressRange::GetBaseAddress() const
+{
+ return m_base_addr;
+}
+
+addr_t
+AddressRange::GetByteSize() const
+{
+ return m_byte_size;
+}
+
+void
+AddressRange::SetByteSize(addr_t byte_size)
+{
+ m_byte_size = byte_size;
+}
+
+//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, Process *process) const
+{
+ if (addr.GetSection() == m_base_addr.GetSection())
+ return (addr.GetOffset() - m_base_addr.GetOffset()) < GetByteSize();
+ addr_t load_base_addr = GetBaseAddress().GetLoadAddress(process);
+ if (load_base_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ addr_t load_addr = addr.GetLoadAddress(process);
+ 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, Process *process) const
+{
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ addr_t load_base_addr = GetBaseAddress().GetLoadAddress(process);
+ 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, Process *process, Address::DumpStyle style, Address::DumpStyle fallback_style) const
+{
+ addr_t vmaddr = LLDB_INVALID_ADDRESS;
+ int addr_size = sizeof (addr_t);
+ if (process)
+ addr_size = process->GetAddressByteSize ();
+
+ switch (style)
+ {
+ case Address::DumpStyleSectionNameOffset:
+ case Address::DumpStyleSectionPointerOffset:
+ s->PutChar ('[');
+ m_base_addr.Dump(s, process, style, fallback_style);
+ s->PutChar ('-');
+ s->Address (m_base_addr.GetOffset() + GetByteSize(), addr_size);
+ s->PutChar (')');
+ return true;
+ break;
+
+ case Address::DumpStyleFileAddress:
+ vmaddr = m_base_addr.GetFileAddress();
+ break;
+
+ case Address::DumpStyleLoadAddress:
+ vmaddr = m_base_addr.GetLoadAddress(process);
+ break;
+ }
+
+ if (vmaddr != LLDB_INVALID_ADDRESS)
+ {
+ s->AddressRange(vmaddr, vmaddr + GetByteSize(), addr_size);
+ return true;
+ }
+
+ return false;
+}
+
+
+void
+AddressRange::DumpDebug (Stream *s) const
+{
+ s->Printf("%.*p: AddressRange section = %*p, offset = 0x%16.16llx, byte_size = 0x%16.16llx\n", (int)sizeof(void*) * 2, this, (int)sizeof(void*) * 2, m_base_addr.GetSection(), m_base_addr.GetOffset(), GetByteSize());
+}
+
+size_t
+AddressRange::MemorySize () const
+{
+ // Noting special for the memory size of a single AddressRange object,
+ // it is just the size of itself.
+ return sizeof(AddressRange);
+}
+//
+//bool
+//lldb::operator== (const AddressRange& lhs, const AddressRange& rhs)
+//{
+// if (lhs.GetBaseAddress() == rhs.GetBaseAddress())
+// return lhs.GetByteSize() == rhs.GetByteSize();
+// return false;
+//}
diff --git a/lldb/source/Core/AddressResolver.cpp b/lldb/source/Core/AddressResolver.cpp
new file mode 100644
index 00000000000..5369d960f25
--- /dev/null
+++ b/lldb/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/lldb/source/Core/AddressResolverFileLine.cpp b/lldb/source/Core/AddressResolverFileLine.cpp
new file mode 100644
index 00000000000..c4aadcca9c1
--- /dev/null
+++ b/lldb/source/Core/AddressResolverFileLine.cpp
@@ -0,0 +1,100 @@
+//===-- 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/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 (int 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%llx 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/lldb/source/Core/AddressResolverName.cpp b/lldb/source/Core/AddressResolverName.cpp
new file mode 100644
index 00000000000..9e154c6e703
--- /dev/null
+++ b/lldb/source/Core/AddressResolverName.cpp
@@ -0,0 +1,231 @@
+//===-- 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/StreamString.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;
+ }
+
+ 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, false, 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, true, 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->GetAddressRangePtr())
+ {
+ if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRangePtr()->GetBaseAddress())
+ {
+ 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->GetAddressRangePtr())
+ {
+ func_addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress();
+ addr_t byte_size = sc.symbol->GetAddressRangePtr()->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/lldb/source/Core/ArchSpec.cpp b/lldb/source/Core/ArchSpec.cpp
new file mode 100644
index 00000000000..3cc8232ac97
--- /dev/null
+++ b/lldb/source/Core/ArchSpec.cpp
@@ -0,0 +1,1681 @@
+//===-- 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 <mach/mach.h>
+#include <mach-o/nlist.h>
+
+#include <string>
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define ARCH_SPEC_SEPARATOR_CHAR '-'
+
+#ifndef CPU_TYPE_ARM
+#define CPU_TYPE_ARM ((cpu_type_t) 12)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_ALL
+#define CPU_SUBTYPE_ARM_ALL ((cpu_subtype_t) 0)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V4T
+#define CPU_SUBTYPE_ARM_V4T ((cpu_subtype_t) 5)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V6
+#define CPU_SUBTYPE_ARM_V6 ((cpu_subtype_t) 6)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V5TEJ
+#define CPU_SUBTYPE_ARM_V5TEJ ((cpu_subtype_t) 7)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_XSCALE
+#define CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V7
+#define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9)
+#endif
+
+//----------------------------------------------------------------------
+// A structure that describes all of the information we want to know
+// about each architecture.
+//----------------------------------------------------------------------
+struct ArchDefinition
+{
+ uint32_t cpu;
+ uint32_t sub;
+ const char *name;
+};
+
+//----------------------------------------------------------------------
+// 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 ArchDefinition g_arch_defs[] =
+{
+ { CPU_TYPE_ANY, CPU_TYPE_ANY , "all" },
+ { CPU_TYPE_ARM, CPU_TYPE_ANY , "arm" },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_ALL , "arm" },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V4T , "armv4" },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V5TEJ , "armv5" },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6 , "armv6" },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7 , "armv7" },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_XSCALE , "xscale" },
+ { CPU_TYPE_POWERPC, CPU_TYPE_ANY , "ppc" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL , "ppc" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_601 , "ppc601" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_602 , "ppc602" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_603 , "ppc603" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_603e , "ppc603e" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_603ev , "ppc603ev" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_604 , "ppc604" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_604e , "ppc604e" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_620 , "ppc620" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_750 , "ppc750" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_7400 , "ppc7400" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_7450 , "ppc7450" },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_970 , "ppc970" },
+ { CPU_TYPE_POWERPC64, CPU_SUBTYPE_POWERPC_ALL , "ppc64" },
+ { CPU_TYPE_POWERPC64, CPU_SUBTYPE_POWERPC_970 , "ppc970-64" },
+ { CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL , "i386" },
+ { CPU_TYPE_I386, CPU_SUBTYPE_486 , "i486" },
+ { CPU_TYPE_I386, CPU_SUBTYPE_486SX , "i486sx" },
+ { CPU_TYPE_I386, CPU_TYPE_ANY , "i386" },
+ { CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL , "x86_64" },
+ { CPU_TYPE_X86_64, CPU_TYPE_ANY , "x86_64" },
+
+ // TODO: when we get a platform that knows more about the host OS we should
+ // let it call some accessor funcitons to set the default system arch for
+ // the default, 32 and 64 bit cases instead of hard coding it in this
+ // table.
+
+#if defined (__i386__) || defined(__x86_64__)
+ { CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL , LLDB_ARCH_DEFAULT },
+ { CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL , LLDB_ARCH_DEFAULT_32BIT },
+ { CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL , LLDB_ARCH_DEFAULT_64BIT },
+#elif defined (__arm__)
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6 , LLDB_ARCH_DEFAULT },
+ { CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6 , LLDB_ARCH_DEFAULT_32BIT },
+#elif defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_7400 , LLDB_ARCH_DEFAULT },
+ { CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_7400 , LLDB_ARCH_DEFAULT_32BIT },
+ { CPU_TYPE_POWERPC64, CPU_SUBTYPE_POWERPC_970 , LLDB_ARCH_DEFAULT_64BIT },
+#endif
+};
+
+//----------------------------------------------------------------------
+// Figure out how many architecture definitions we have
+//----------------------------------------------------------------------
+const size_t k_num_arch_defs = sizeof(g_arch_defs)/sizeof(ArchDefinition);
+
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+ArchSpec::ArchSpec() :
+ m_cpu (LLDB_INVALID_CPUTYPE),
+ m_sub (0)
+{
+}
+
+//----------------------------------------------------------------------
+// Constructor that initializes the object with supplied cpu and
+// subtypes.
+//----------------------------------------------------------------------
+ArchSpec::ArchSpec(uint32_t cpu, uint32_t sub) :
+ m_cpu (cpu),
+ m_sub (sub)
+{
+}
+
+//----------------------------------------------------------------------
+// Constructor that initializes the object with supplied
+// architecture name. There are also predefined values in
+// Defines.h:
+// liblldb_ARCH_DEFAULT
+// The arch the current system defaults to when a program is
+// launched without any extra attributes or settings.
+//
+// liblldb_ARCH_DEFAULT_32BIT
+// The 32 bit arch the current system defaults to (if any)
+//
+// liblldb_ARCH_DEFAULT_32BIT
+// The 64 bit arch the current system defaults to (if any)
+//----------------------------------------------------------------------
+ArchSpec::ArchSpec(const char *arch_name) :
+ m_cpu (LLDB_INVALID_CPUTYPE),
+ m_sub (0)
+{
+ if (arch_name)
+ SetArch(arch_name);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ArchSpec::~ArchSpec()
+{
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const ArchSpec&
+ArchSpec::operator= (const ArchSpec& rhs)
+{
+ if (this != &rhs)
+ {
+ m_cpu = rhs.m_cpu;
+ m_sub = rhs.m_sub;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Get a C string representation of the current architecture
+//----------------------------------------------------------------------
+const char *
+ArchSpec::AsCString() const
+{
+ return ArchSpec::AsCString(m_cpu, m_sub);
+}
+
+//----------------------------------------------------------------------
+// Class function to get a C string representation given a CPU type
+// and subtype.
+//----------------------------------------------------------------------
+const char *
+ArchSpec::AsCString(uint32_t cpu, uint32_t sub)
+{
+ for (uint32_t i=0; i<k_num_arch_defs; i++)
+ {
+ if (cpu == g_arch_defs[i].cpu)
+ {
+ if (sub == g_arch_defs[i].sub)
+ return g_arch_defs[i].name;
+ else if (sub != CPU_TYPE_ANY && sub != LLDB_INVALID_CPUTYPE)
+ {
+ if ((sub & ~CPU_SUBTYPE_MASK) == g_arch_defs[i].sub)
+ return g_arch_defs[i].name;
+ }
+ }
+ }
+ static char s_cpu_hex_str[64];
+ ::snprintf(s_cpu_hex_str, sizeof(s_cpu_hex_str), "%u%c%u", cpu, ARCH_SPEC_SEPARATOR_CHAR, sub);
+ return s_cpu_hex_str;
+}
+
+//----------------------------------------------------------------------
+// Clears the object contents back to a default invalid state.
+//----------------------------------------------------------------------
+void
+ArchSpec::Clear()
+{
+ m_cpu = LLDB_INVALID_CPUTYPE;
+ m_sub = 0;
+}
+
+
+//----------------------------------------------------------------------
+// CPU subtype get accessor.
+//----------------------------------------------------------------------
+uint32_t
+ArchSpec::GetCPUSubtype() const
+{
+ if (m_sub == CPU_TYPE_ANY || m_sub == LLDB_INVALID_CPUTYPE)
+ return m_sub;
+ return m_sub & ~CPU_SUBTYPE_MASK;
+}
+
+
+//----------------------------------------------------------------------
+// CPU type get accessor.
+//----------------------------------------------------------------------
+uint32_t
+ArchSpec::GetCPUType() const
+{
+ return m_cpu;
+}
+
+
+//----------------------------------------------------------------------
+// Feature flags get accessor.
+//----------------------------------------------------------------------
+uint32_t
+ArchSpec::GetFeatureFlags() const
+{
+ if (m_sub == CPU_TYPE_ANY || m_sub == LLDB_INVALID_CPUTYPE)
+ return 0;
+ return m_sub & CPU_SUBTYPE_MASK;
+}
+
+
+static const char * g_i386_dwarf_reg_names[] =
+{
+ "eax",
+ "ecx",
+ "edx",
+ "ebx",
+ "esp",
+ "ebp",
+ "esi",
+ "edi",
+ "eip",
+ "eflags"
+};
+
+static const char * g_i386_gcc_reg_names[] =
+{
+ "eax",
+ "ecx",
+ "edx",
+ "ebx",
+ "ebp",
+ "esp",
+ "esi",
+ "edi",
+ "eip",
+ "eflags"
+};
+
+static const char * g_x86_64_dwarf_and_gcc_reg_names[] = {
+ "rax",
+ "rdx",
+ "rcx",
+ "rbx",
+ "rsi",
+ "rdi",
+ "rbp",
+ "rsp",
+ "r8",
+ "r9",
+ "r10",
+ "r11",
+ "r12",
+ "r13",
+ "r14",
+ "r15",
+ "rip"
+};
+
+// Values take from:
+// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf
+
+enum
+{
+ eRegNumARM_DWARF_r0 = 0,
+ eRegNumARM_DWARF_r1 = 1,
+ eRegNumARM_DWARF_r2 = 2,
+ eRegNumARM_DWARF_r3 = 3,
+ eRegNumARM_DWARF_r4 = 4,
+ eRegNumARM_DWARF_r5 = 5,
+ eRegNumARM_DWARF_r6 = 6,
+ eRegNumARM_DWARF_r7 = 7,
+ eRegNumARM_DWARF_r8 = 8,
+ eRegNumARM_DWARF_r9 = 9,
+ eRegNumARM_DWARF_r10 = 10,
+ eRegNumARM_DWARF_r11 = 11,
+ eRegNumARM_DWARF_r12 = 12,
+ eRegNumARM_DWARF_r13 = 13, // SP
+ eRegNumARM_DWARF_r14 = 14, // LR
+ eRegNumARM_DWARF_r15 = 15, // PC
+
+ eRegNumARM_DWARF_f0_obsolete= 16,
+ eRegNumARM_DWARF_f1_obsolete,
+ eRegNumARM_DWARF_f2_obsolete,
+ eRegNumARM_DWARF_f3_obsolete,
+ eRegNumARM_DWARF_f4_obsolete,
+ eRegNumARM_DWARF_f5_obsolete,
+ eRegNumARM_DWARF_f6_obsolete,
+ eRegNumARM_DWARF_f7_obsolete,
+
+ eRegNumARM_DWARF_s0_obsolete = 16,
+ eRegNumARM_DWARF_s1_obsolete,
+ eRegNumARM_DWARF_s2_obsolete,
+ eRegNumARM_DWARF_s3_obsolete,
+ eRegNumARM_DWARF_s4_obsolete,
+ eRegNumARM_DWARF_s5_obsolete,
+ eRegNumARM_DWARF_s6_obsolete,
+ eRegNumARM_DWARF_s7_obsolete,
+ eRegNumARM_DWARF_s8_obsolete,
+ eRegNumARM_DWARF_s9_obsolete,
+ eRegNumARM_DWARF_s10_obsolete,
+ eRegNumARM_DWARF_s11_obsolete,
+ eRegNumARM_DWARF_s12_obsolete,
+ eRegNumARM_DWARF_s13_obsolete,
+ eRegNumARM_DWARF_s14_obsolete,
+ eRegNumARM_DWARF_s15_obsolete,
+ eRegNumARM_DWARF_s16_obsolete,
+ eRegNumARM_DWARF_s17_obsolete,
+ eRegNumARM_DWARF_s18_obsolete,
+ eRegNumARM_DWARF_s19_obsolete,
+ eRegNumARM_DWARF_s20_obsolete,
+ eRegNumARM_DWARF_s21_obsolete,
+ eRegNumARM_DWARF_s22_obsolete,
+ eRegNumARM_DWARF_s23_obsolete,
+ eRegNumARM_DWARF_s24_obsolete,
+ eRegNumARM_DWARF_s25_obsolete,
+ eRegNumARM_DWARF_s26_obsolete,
+ eRegNumARM_DWARF_s27_obsolete,
+ eRegNumARM_DWARF_s28_obsolete,
+ eRegNumARM_DWARF_s29_obsolete,
+ eRegNumARM_DWARF_s30_obsolete,
+ eRegNumARM_DWARF_s31_obsolete,
+
+ eRegNumARM_DWARF_s0 = 64,
+ eRegNumARM_DWARF_s1,
+ eRegNumARM_DWARF_s2,
+ eRegNumARM_DWARF_s3,
+ eRegNumARM_DWARF_s4,
+ eRegNumARM_DWARF_s5,
+ eRegNumARM_DWARF_s6,
+ eRegNumARM_DWARF_s7,
+ eRegNumARM_DWARF_s8,
+ eRegNumARM_DWARF_s9,
+ eRegNumARM_DWARF_s10,
+ eRegNumARM_DWARF_s11,
+ eRegNumARM_DWARF_s12,
+ eRegNumARM_DWARF_s13,
+ eRegNumARM_DWARF_s14,
+ eRegNumARM_DWARF_s15,
+ eRegNumARM_DWARF_s16,
+ eRegNumARM_DWARF_s17,
+ eRegNumARM_DWARF_s18,
+ eRegNumARM_DWARF_s19,
+ eRegNumARM_DWARF_s20,
+ eRegNumARM_DWARF_s21,
+ eRegNumARM_DWARF_s22,
+ eRegNumARM_DWARF_s23,
+ eRegNumARM_DWARF_s24,
+ eRegNumARM_DWARF_s25,
+ eRegNumARM_DWARF_s26,
+ eRegNumARM_DWARF_s27,
+ eRegNumARM_DWARF_s28,
+ eRegNumARM_DWARF_s29,
+ eRegNumARM_DWARF_s30,
+ eRegNumARM_DWARF_s31,
+
+ eRegNumARM_DWARF_f0 = 96,
+ eRegNumARM_DWARF_f1,
+ eRegNumARM_DWARF_f2,
+ eRegNumARM_DWARF_f3,
+ eRegNumARM_DWARF_f4,
+ eRegNumARM_DWARF_f5,
+ eRegNumARM_DWARF_f6,
+ eRegNumARM_DWARF_f7,
+
+ eRegNumARM_DWARF_ACC0 = 104,
+ eRegNumARM_DWARF_ACC1,
+ eRegNumARM_DWARF_ACC2,
+ eRegNumARM_DWARF_ACC3,
+ eRegNumARM_DWARF_ACC4,
+ eRegNumARM_DWARF_ACC5,
+ eRegNumARM_DWARF_ACC6,
+ eRegNumARM_DWARF_ACC7,
+
+ eRegNumARM_DWARF_wCGR0 = 104, // These overlap with ACC0-ACC7
+ eRegNumARM_DWARF_wCGR1,
+ eRegNumARM_DWARF_wCGR2,
+ eRegNumARM_DWARF_wCGR3,
+ eRegNumARM_DWARF_wCGR4,
+ eRegNumARM_DWARF_wCGR5,
+ eRegNumARM_DWARF_wCGR6,
+ eRegNumARM_DWARF_wCGR7,
+
+ eRegNumARM_DWARF_wR0 = 112,
+ eRegNumARM_DWARF_wR1,
+ eRegNumARM_DWARF_wR2,
+ eRegNumARM_DWARF_wR3,
+ eRegNumARM_DWARF_wR4,
+ eRegNumARM_DWARF_wR5,
+ eRegNumARM_DWARF_wR6,
+ eRegNumARM_DWARF_wR7,
+ eRegNumARM_DWARF_wR8,
+ eRegNumARM_DWARF_wR9,
+ eRegNumARM_DWARF_wR10,
+ eRegNumARM_DWARF_wR11,
+ eRegNumARM_DWARF_wR12,
+ eRegNumARM_DWARF_wR13,
+ eRegNumARM_DWARF_wR14,
+ eRegNumARM_DWARF_wR15,
+
+ eRegNumARM_DWARF_spsr = 128,
+ eRegNumARM_DWARF_spsr_fiq,
+ eRegNumARM_DWARF_spsr_irq,
+ eRegNumARM_DWARF_spsr_abt,
+ eRegNumARM_DWARF_spsr_und,
+ eRegNumARM_DWARF_spsr_svc,
+
+ eRegNumARM_DWARF_r8_usr = 144,
+ eRegNumARM_DWARF_r9_usr,
+ eRegNumARM_DWARF_r10_usr,
+ eRegNumARM_DWARF_r11_usr,
+ eRegNumARM_DWARF_r12_usr,
+ eRegNumARM_DWARF_r13_usr,
+ eRegNumARM_DWARF_r14_usr,
+
+ eRegNumARM_DWARF_r8_fiq = 151,
+ eRegNumARM_DWARF_r9_fiq,
+ eRegNumARM_DWARF_r10_fiq,
+ eRegNumARM_DWARF_r11_fiq,
+ eRegNumARM_DWARF_r12_fiq,
+ eRegNumARM_DWARF_r13_fiq,
+ eRegNumARM_DWARF_r14_fiq,
+
+ eRegNumARM_DWARF_r13_irq,
+ eRegNumARM_DWARF_r14_irq,
+
+ eRegNumARM_DWARF_r13_abt,
+ eRegNumARM_DWARF_r14_abt,
+
+ eRegNumARM_DWARF_r13_und,
+ eRegNumARM_DWARF_r14_und,
+
+ eRegNumARM_DWARF_r13_svc,
+ eRegNumARM_DWARF_r14_svc,
+
+ eRegNumARM_DWARF_wC0 = 192,
+ eRegNumARM_DWARF_wC1,
+ eRegNumARM_DWARF_wC2,
+ eRegNumARM_DWARF_wC3,
+ eRegNumARM_DWARF_wC4,
+ eRegNumARM_DWARF_wC5,
+ eRegNumARM_DWARF_wC6,
+ eRegNumARM_DWARF_wC7,
+
+ eRegNumARM_DWARF_d0 = 256, // VFP-v3/NEON D0-D31 (32 64 bit registers)
+ eRegNumARM_DWARF_d1,
+ eRegNumARM_DWARF_d2,
+ eRegNumARM_DWARF_d3,
+ eRegNumARM_DWARF_d4,
+ eRegNumARM_DWARF_d5,
+ eRegNumARM_DWARF_d6,
+ eRegNumARM_DWARF_d7,
+ eRegNumARM_DWARF_d8,
+ eRegNumARM_DWARF_d9,
+ eRegNumARM_DWARF_d10,
+ eRegNumARM_DWARF_d11,
+ eRegNumARM_DWARF_d12,
+ eRegNumARM_DWARF_d13,
+ eRegNumARM_DWARF_d14,
+ eRegNumARM_DWARF_d15,
+ eRegNumARM_DWARF_d16,
+ eRegNumARM_DWARF_d17,
+ eRegNumARM_DWARF_d18,
+ eRegNumARM_DWARF_d19,
+ eRegNumARM_DWARF_d20,
+ eRegNumARM_DWARF_d21,
+ eRegNumARM_DWARF_d22,
+ eRegNumARM_DWARF_d23,
+ eRegNumARM_DWARF_d24,
+ eRegNumARM_DWARF_d25,
+ eRegNumARM_DWARF_d26,
+ eRegNumARM_DWARF_d27,
+ eRegNumARM_DWARF_d28,
+ eRegNumARM_DWARF_d29,
+ eRegNumARM_DWARF_d30,
+ eRegNumARM_DWARF_d31
+};
+
+// Register numbering definitions for 32 and 64 bit ppc for RegisterNumberingType::Dwarf
+enum
+{
+ eRegNumPPC_DWARF_r0 = 0,
+ eRegNumPPC_DWARF_r1 = 1,
+ eRegNumPPC_DWARF_r2 = 2,
+ eRegNumPPC_DWARF_r3 = 3,
+ eRegNumPPC_DWARF_r4 = 4,
+ eRegNumPPC_DWARF_r5 = 5,
+ eRegNumPPC_DWARF_r6 = 6,
+ eRegNumPPC_DWARF_r7 = 7,
+ eRegNumPPC_DWARF_r8 = 8,
+ eRegNumPPC_DWARF_r9 = 9,
+ eRegNumPPC_DWARF_r10 = 10,
+ eRegNumPPC_DWARF_r11 = 11,
+ eRegNumPPC_DWARF_r12 = 12,
+ eRegNumPPC_DWARF_r13 = 13,
+ eRegNumPPC_DWARF_r14 = 14,
+ eRegNumPPC_DWARF_r15 = 15,
+ eRegNumPPC_DWARF_r16 = 16,
+ eRegNumPPC_DWARF_r17 = 17,
+ eRegNumPPC_DWARF_r18 = 18,
+ eRegNumPPC_DWARF_r19 = 19,
+ eRegNumPPC_DWARF_r20 = 20,
+ eRegNumPPC_DWARF_r21 = 21,
+ eRegNumPPC_DWARF_r22 = 22,
+ eRegNumPPC_DWARF_r23 = 23,
+ eRegNumPPC_DWARF_r24 = 24,
+ eRegNumPPC_DWARF_r25 = 25,
+ eRegNumPPC_DWARF_r26 = 26,
+ eRegNumPPC_DWARF_r27 = 27,
+ eRegNumPPC_DWARF_r28 = 28,
+ eRegNumPPC_DWARF_r29 = 29,
+ eRegNumPPC_DWARF_r30 = 30,
+ eRegNumPPC_DWARF_r31 = 31,
+
+ eRegNumPPC_DWARF_fr0 = 32,
+ eRegNumPPC_DWARF_fr1 = 33,
+ eRegNumPPC_DWARF_fr2 = 34,
+ eRegNumPPC_DWARF_fr3 = 35,
+ eRegNumPPC_DWARF_fr4 = 36,
+ eRegNumPPC_DWARF_fr5 = 37,
+ eRegNumPPC_DWARF_fr6 = 38,
+ eRegNumPPC_DWARF_fr7 = 39,
+ eRegNumPPC_DWARF_fr8 = 40,
+ eRegNumPPC_DWARF_fr9 = 41,
+ eRegNumPPC_DWARF_fr10 = 42,
+ eRegNumPPC_DWARF_fr11 = 43,
+ eRegNumPPC_DWARF_fr12 = 44,
+ eRegNumPPC_DWARF_fr13 = 45,
+ eRegNumPPC_DWARF_fr14 = 46,
+ eRegNumPPC_DWARF_fr15 = 47,
+ eRegNumPPC_DWARF_fr16 = 48,
+ eRegNumPPC_DWARF_fr17 = 49,
+ eRegNumPPC_DWARF_fr18 = 50,
+ eRegNumPPC_DWARF_fr19 = 51,
+ eRegNumPPC_DWARF_fr20 = 52,
+ eRegNumPPC_DWARF_fr21 = 53,
+ eRegNumPPC_DWARF_fr22 = 54,
+ eRegNumPPC_DWARF_fr23 = 55,
+ eRegNumPPC_DWARF_fr24 = 56,
+ eRegNumPPC_DWARF_fr25 = 57,
+ eRegNumPPC_DWARF_fr26 = 58,
+ eRegNumPPC_DWARF_fr27 = 59,
+ eRegNumPPC_DWARF_fr28 = 60,
+ eRegNumPPC_DWARF_fr29 = 61,
+ eRegNumPPC_DWARF_fr30 = 62,
+ eRegNumPPC_DWARF_fr31 = 63,
+
+ eRegNumPPC_DWARF_cr = 64,
+ eRegNumPPC_DWARF_fpscr = 65,
+ eRegNumPPC_DWARF_msr = 66,
+ eRegNumPPC_DWARF_vscr = 67,
+
+ eRegNumPPC_DWARF_sr0 = 70,
+ eRegNumPPC_DWARF_sr1,
+ eRegNumPPC_DWARF_sr2,
+ eRegNumPPC_DWARF_sr3,
+ eRegNumPPC_DWARF_sr4,
+ eRegNumPPC_DWARF_sr5,
+ eRegNumPPC_DWARF_sr6,
+ eRegNumPPC_DWARF_sr7,
+ eRegNumPPC_DWARF_sr8,
+ eRegNumPPC_DWARF_sr9,
+ eRegNumPPC_DWARF_sr10,
+ eRegNumPPC_DWARF_sr11,
+ eRegNumPPC_DWARF_sr12,
+ eRegNumPPC_DWARF_sr13,
+ eRegNumPPC_DWARF_sr14,
+ eRegNumPPC_DWARF_sr15,
+
+
+ eRegNumPPC_DWARF_acc = 99,
+ eRegNumPPC_DWARF_mq = 100,
+ eRegNumPPC_DWARF_xer = 101,
+ eRegNumPPC_DWARF_rtcu = 104,
+ eRegNumPPC_DWARF_rtcl = 105,
+
+ eRegNumPPC_DWARF_lr = 108,
+ eRegNumPPC_DWARF_ctr = 109,
+
+ eRegNumPPC_DWARF_dsisr = 118,
+ eRegNumPPC_DWARF_dar = 119,
+ eRegNumPPC_DWARF_dec = 122,
+ eRegNumPPC_DWARF_sdr1 = 125,
+ eRegNumPPC_DWARF_srr0 = 126,
+ eRegNumPPC_DWARF_srr1 = 127,
+
+ eRegNumPPC_DWARF_vrsave = 356,
+ eRegNumPPC_DWARF_sprg0 = 372,
+ eRegNumPPC_DWARF_sprg1,
+ eRegNumPPC_DWARF_sprg2,
+ eRegNumPPC_DWARF_sprg3,
+
+ eRegNumPPC_DWARF_asr = 380,
+ eRegNumPPC_DWARF_ear = 382,
+ eRegNumPPC_DWARF_tb = 384,
+ eRegNumPPC_DWARF_tbu = 385,
+ eRegNumPPC_DWARF_pvr = 387,
+
+ eRegNumPPC_DWARF_spefscr = 612,
+
+ eRegNumPPC_DWARF_ibat0u = 628,
+ eRegNumPPC_DWARF_ibat0l = 629,
+ eRegNumPPC_DWARF_ibat1u = 630,
+ eRegNumPPC_DWARF_ibat1l = 631,
+ eRegNumPPC_DWARF_ibat2u = 632,
+ eRegNumPPC_DWARF_ibat2l = 633,
+ eRegNumPPC_DWARF_ibat3u = 634,
+ eRegNumPPC_DWARF_ibat3l = 635,
+ eRegNumPPC_DWARF_dbat0u = 636,
+ eRegNumPPC_DWARF_dbat0l = 637,
+ eRegNumPPC_DWARF_dbat1u = 638,
+ eRegNumPPC_DWARF_dbat1l = 639,
+ eRegNumPPC_DWARF_dbat2u = 640,
+ eRegNumPPC_DWARF_dbat2l = 641,
+ eRegNumPPC_DWARF_dbat3u = 642,
+ eRegNumPPC_DWARF_dbat3l = 643,
+
+ eRegNumPPC_DWARF_hid0 = 1108,
+ eRegNumPPC_DWARF_hid1,
+ eRegNumPPC_DWARF_hid2,
+ eRegNumPPC_DWARF_hid3,
+ eRegNumPPC_DWARF_hid4,
+ eRegNumPPC_DWARF_hid5,
+ eRegNumPPC_DWARF_hid6,
+ eRegNumPPC_DWARF_hid7,
+ eRegNumPPC_DWARF_hid8,
+ eRegNumPPC_DWARF_hid9,
+ eRegNumPPC_DWARF_hid10,
+ eRegNumPPC_DWARF_hid11,
+ eRegNumPPC_DWARF_hid12,
+ eRegNumPPC_DWARF_hid13,
+ eRegNumPPC_DWARF_hid14,
+ eRegNumPPC_DWARF_hid15,
+
+ eRegNumPPC_DWARF_vr0 = 1124,
+ eRegNumPPC_DWARF_vr1,
+ eRegNumPPC_DWARF_vr2,
+ eRegNumPPC_DWARF_vr3,
+ eRegNumPPC_DWARF_vr4,
+ eRegNumPPC_DWARF_vr5,
+ eRegNumPPC_DWARF_vr6,
+ eRegNumPPC_DWARF_vr7,
+ eRegNumPPC_DWARF_vr8,
+ eRegNumPPC_DWARF_vr9,
+ eRegNumPPC_DWARF_vr10,
+ eRegNumPPC_DWARF_vr11,
+ eRegNumPPC_DWARF_vr12,
+ eRegNumPPC_DWARF_vr13,
+ eRegNumPPC_DWARF_vr14,
+ eRegNumPPC_DWARF_vr15,
+ eRegNumPPC_DWARF_vr16,
+ eRegNumPPC_DWARF_vr17,
+ eRegNumPPC_DWARF_vr18,
+ eRegNumPPC_DWARF_vr19,
+ eRegNumPPC_DWARF_vr20,
+ eRegNumPPC_DWARF_vr21,
+ eRegNumPPC_DWARF_vr22,
+ eRegNumPPC_DWARF_vr23,
+ eRegNumPPC_DWARF_vr24,
+ eRegNumPPC_DWARF_vr25,
+ eRegNumPPC_DWARF_vr26,
+ eRegNumPPC_DWARF_vr27,
+ eRegNumPPC_DWARF_vr28,
+ eRegNumPPC_DWARF_vr29,
+ eRegNumPPC_DWARF_vr30,
+ eRegNumPPC_DWARF_vr31,
+
+ eRegNumPPC_DWARF_ev0 = 1200,
+ eRegNumPPC_DWARF_ev1,
+ eRegNumPPC_DWARF_ev2,
+ eRegNumPPC_DWARF_ev3,
+ eRegNumPPC_DWARF_ev4,
+ eRegNumPPC_DWARF_ev5,
+ eRegNumPPC_DWARF_ev6,
+ eRegNumPPC_DWARF_ev7,
+ eRegNumPPC_DWARF_ev8,
+ eRegNumPPC_DWARF_ev9,
+ eRegNumPPC_DWARF_ev10,
+ eRegNumPPC_DWARF_ev11,
+ eRegNumPPC_DWARF_ev12,
+ eRegNumPPC_DWARF_ev13,
+ eRegNumPPC_DWARF_ev14,
+ eRegNumPPC_DWARF_ev15,
+ eRegNumPPC_DWARF_ev16,
+ eRegNumPPC_DWARF_ev17,
+ eRegNumPPC_DWARF_ev18,
+ eRegNumPPC_DWARF_ev19,
+ eRegNumPPC_DWARF_ev20,
+ eRegNumPPC_DWARF_ev21,
+ eRegNumPPC_DWARF_ev22,
+ eRegNumPPC_DWARF_ev23,
+ eRegNumPPC_DWARF_ev24,
+ eRegNumPPC_DWARF_ev25,
+ eRegNumPPC_DWARF_ev26,
+ eRegNumPPC_DWARF_ev27,
+ eRegNumPPC_DWARF_ev28,
+ eRegNumPPC_DWARF_ev29,
+ eRegNumPPC_DWARF_ev30,
+ eRegNumPPC_DWARF_ev31
+};
+
+// Register numbering definitions for 32 and 64 bit ppc for RegisterNumberingType::GCC
+enum
+{
+ eRegNumPPC_GCC_r0 = 0,
+ eRegNumPPC_GCC_r1 = 1,
+ eRegNumPPC_GCC_r2 = 2,
+ eRegNumPPC_GCC_r3 = 3,
+ eRegNumPPC_GCC_r4 = 4,
+ eRegNumPPC_GCC_r5 = 5,
+ eRegNumPPC_GCC_r6 = 6,
+ eRegNumPPC_GCC_r7 = 7,
+ eRegNumPPC_GCC_r8 = 8,
+ eRegNumPPC_GCC_r9 = 9,
+ eRegNumPPC_GCC_r10 = 10,
+ eRegNumPPC_GCC_r11 = 11,
+ eRegNumPPC_GCC_r12 = 12,
+ eRegNumPPC_GCC_r13 = 13,
+ eRegNumPPC_GCC_r14 = 14,
+ eRegNumPPC_GCC_r15 = 15,
+ eRegNumPPC_GCC_r16 = 16,
+ eRegNumPPC_GCC_r17 = 17,
+ eRegNumPPC_GCC_r18 = 18,
+ eRegNumPPC_GCC_r19 = 19,
+ eRegNumPPC_GCC_r20 = 20,
+ eRegNumPPC_GCC_r21 = 21,
+ eRegNumPPC_GCC_r22 = 22,
+ eRegNumPPC_GCC_r23 = 23,
+ eRegNumPPC_GCC_r24 = 24,
+ eRegNumPPC_GCC_r25 = 25,
+ eRegNumPPC_GCC_r26 = 26,
+ eRegNumPPC_GCC_r27 = 27,
+ eRegNumPPC_GCC_r28 = 28,
+ eRegNumPPC_GCC_r29 = 29,
+ eRegNumPPC_GCC_r30 = 30,
+ eRegNumPPC_GCC_r31 = 31,
+ eRegNumPPC_GCC_fr0 = 32,
+ eRegNumPPC_GCC_fr1 = 33,
+ eRegNumPPC_GCC_fr2 = 34,
+ eRegNumPPC_GCC_fr3 = 35,
+ eRegNumPPC_GCC_fr4 = 36,
+ eRegNumPPC_GCC_fr5 = 37,
+ eRegNumPPC_GCC_fr6 = 38,
+ eRegNumPPC_GCC_fr7 = 39,
+ eRegNumPPC_GCC_fr8 = 40,
+ eRegNumPPC_GCC_fr9 = 41,
+ eRegNumPPC_GCC_fr10 = 42,
+ eRegNumPPC_GCC_fr11 = 43,
+ eRegNumPPC_GCC_fr12 = 44,
+ eRegNumPPC_GCC_fr13 = 45,
+ eRegNumPPC_GCC_fr14 = 46,
+ eRegNumPPC_GCC_fr15 = 47,
+ eRegNumPPC_GCC_fr16 = 48,
+ eRegNumPPC_GCC_fr17 = 49,
+ eRegNumPPC_GCC_fr18 = 50,
+ eRegNumPPC_GCC_fr19 = 51,
+ eRegNumPPC_GCC_fr20 = 52,
+ eRegNumPPC_GCC_fr21 = 53,
+ eRegNumPPC_GCC_fr22 = 54,
+ eRegNumPPC_GCC_fr23 = 55,
+ eRegNumPPC_GCC_fr24 = 56,
+ eRegNumPPC_GCC_fr25 = 57,
+ eRegNumPPC_GCC_fr26 = 58,
+ eRegNumPPC_GCC_fr27 = 59,
+ eRegNumPPC_GCC_fr28 = 60,
+ eRegNumPPC_GCC_fr29 = 61,
+ eRegNumPPC_GCC_fr30 = 62,
+ eRegNumPPC_GCC_fr31 = 63,
+ eRegNumPPC_GCC_mq = 64,
+ eRegNumPPC_GCC_lr = 65,
+ eRegNumPPC_GCC_ctr = 66,
+ eRegNumPPC_GCC_ap = 67,
+ eRegNumPPC_GCC_cr0 = 68,
+ eRegNumPPC_GCC_cr1 = 69,
+ eRegNumPPC_GCC_cr2 = 70,
+ eRegNumPPC_GCC_cr3 = 71,
+ eRegNumPPC_GCC_cr4 = 72,
+ eRegNumPPC_GCC_cr5 = 73,
+ eRegNumPPC_GCC_cr6 = 74,
+ eRegNumPPC_GCC_cr7 = 75,
+ eRegNumPPC_GCC_xer = 76,
+ eRegNumPPC_GCC_v0 = 77,
+ eRegNumPPC_GCC_v1 = 78,
+ eRegNumPPC_GCC_v2 = 79,
+ eRegNumPPC_GCC_v3 = 80,
+ eRegNumPPC_GCC_v4 = 81,
+ eRegNumPPC_GCC_v5 = 82,
+ eRegNumPPC_GCC_v6 = 83,
+ eRegNumPPC_GCC_v7 = 84,
+ eRegNumPPC_GCC_v8 = 85,
+ eRegNumPPC_GCC_v9 = 86,
+ eRegNumPPC_GCC_v10 = 87,
+ eRegNumPPC_GCC_v11 = 88,
+ eRegNumPPC_GCC_v12 = 89,
+ eRegNumPPC_GCC_v13 = 90,
+ eRegNumPPC_GCC_v14 = 91,
+ eRegNumPPC_GCC_v15 = 92,
+ eRegNumPPC_GCC_v16 = 93,
+ eRegNumPPC_GCC_v17 = 94,
+ eRegNumPPC_GCC_v18 = 95,
+ eRegNumPPC_GCC_v19 = 96,
+ eRegNumPPC_GCC_v20 = 97,
+ eRegNumPPC_GCC_v21 = 98,
+ eRegNumPPC_GCC_v22 = 99,
+ eRegNumPPC_GCC_v23 = 100,
+ eRegNumPPC_GCC_v24 = 101,
+ eRegNumPPC_GCC_v25 = 102,
+ eRegNumPPC_GCC_v26 = 103,
+ eRegNumPPC_GCC_v27 = 104,
+ eRegNumPPC_GCC_v28 = 105,
+ eRegNumPPC_GCC_v29 = 106,
+ eRegNumPPC_GCC_v30 = 107,
+ eRegNumPPC_GCC_v31 = 108,
+ eRegNumPPC_GCC_vrsave = 109,
+ eRegNumPPC_GCC_vscr = 110,
+ eRegNumPPC_GCC_spe_acc = 111,
+ eRegNumPPC_GCC_spefscr = 112,
+ eRegNumPPC_GCC_sfp = 113,
+};
+
+static const char * g_arm_gcc_reg_names[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "cc", "sfp", "afp",
+ "mv0", "mv1", "mv2", "mv3", "mv4", "mv5", "mv6", "mv7",
+ "mv8", "mv9", "mv10", "mv11", "mv12", "mv13", "mv14", "mv15",
+ "wcgr0","wcgr1","wcgr2","wcgr3",
+ "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
+ "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
+ "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
+ "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
+ "vfpcc"
+};
+
+//----------------------------------------------------------------------
+// Get register names for the current object architecture given
+// a register number, and a reg_kind for that register number.
+//----------------------------------------------------------------------
+const char *
+ArchSpec::GetRegisterName(uint32_t reg_num, uint32_t reg_kind) const
+{
+ return ArchSpec::GetRegisterName(m_cpu, m_sub, reg_num, reg_kind);
+}
+
+
+//----------------------------------------------------------------------
+// Get register names for the specified CPU type and subtype given
+// a register number, and a reg_kind for that register number.
+//----------------------------------------------------------------------
+const char *
+ArchSpec::GetRegisterName(uint32_t cpu, uint32_t subtype, uint32_t reg_num, uint32_t reg_kind)
+{
+ if (cpu == CPU_TYPE_I386)
+ {
+ switch (reg_kind)
+ {
+ case eRegisterKindGCC:
+ if (reg_num < sizeof(g_i386_gcc_reg_names)/sizeof(const char *))
+ return g_i386_gcc_reg_names[reg_num];
+ break;
+ case eRegisterKindDWARF:
+ if (reg_num < sizeof(g_i386_dwarf_reg_names)/sizeof(const char *))
+ return g_i386_dwarf_reg_names[reg_num];
+ break;
+ default:
+ break;
+ }
+ }
+ else if (cpu == CPU_TYPE_X86_64)
+ {
+ switch (reg_kind)
+ {
+ case eRegisterKindGCC:
+ case eRegisterKindDWARF:
+ if (reg_num < sizeof(g_x86_64_dwarf_and_gcc_reg_names)/sizeof(const char *))
+ return g_x86_64_dwarf_and_gcc_reg_names[reg_num];
+ break;
+ default:
+ break;
+ }
+ }
+ else if (cpu == CPU_TYPE_ARM)
+ {
+ switch (reg_kind)
+ {
+ case eRegisterKindGCC:
+ if (reg_num < sizeof(g_arm_gcc_reg_names)/sizeof(const char *))
+ return g_arm_gcc_reg_names[reg_num];
+ break;
+
+ case eRegisterKindDWARF:
+ switch (reg_num)
+ {
+ case eRegNumARM_DWARF_r0: return "r0";
+ case eRegNumARM_DWARF_r1: return "r1";
+ case eRegNumARM_DWARF_r2: return "r2";
+ case eRegNumARM_DWARF_r3: return "r3";
+ case eRegNumARM_DWARF_r4: return "r4";
+ case eRegNumARM_DWARF_r5: return "r5";
+ case eRegNumARM_DWARF_r6: return "r6";
+ case eRegNumARM_DWARF_r7: return "r7";
+ case eRegNumARM_DWARF_r8: return "r8";
+ case eRegNumARM_DWARF_r9: return "r9";
+ case eRegNumARM_DWARF_r10: return "r10";
+ case eRegNumARM_DWARF_r11: return "r11";
+ case eRegNumARM_DWARF_r12: return "r12";
+ case eRegNumARM_DWARF_r13: return "sp";
+ case eRegNumARM_DWARF_r14: return "lr";
+ case eRegNumARM_DWARF_r15: return "pc";
+ case eRegNumARM_DWARF_s0_obsolete: case eRegNumARM_DWARF_s0: return "s0";
+ case eRegNumARM_DWARF_s1_obsolete: case eRegNumARM_DWARF_s1: return "s1";
+ case eRegNumARM_DWARF_s2_obsolete: case eRegNumARM_DWARF_s2: return "s2";
+ case eRegNumARM_DWARF_s3_obsolete: case eRegNumARM_DWARF_s3: return "s3";
+ case eRegNumARM_DWARF_s4_obsolete: case eRegNumARM_DWARF_s4: return "s4";
+ case eRegNumARM_DWARF_s5_obsolete: case eRegNumARM_DWARF_s5: return "s5";
+ case eRegNumARM_DWARF_s6_obsolete: case eRegNumARM_DWARF_s6: return "s6";
+ case eRegNumARM_DWARF_s7_obsolete: case eRegNumARM_DWARF_s7: return "s7";
+ case eRegNumARM_DWARF_s8_obsolete: case eRegNumARM_DWARF_s8: return "s8";
+ case eRegNumARM_DWARF_s9_obsolete: case eRegNumARM_DWARF_s9: return "s9";
+ case eRegNumARM_DWARF_s10_obsolete: case eRegNumARM_DWARF_s10: return "s10";
+ case eRegNumARM_DWARF_s11_obsolete: case eRegNumARM_DWARF_s11: return "s11";
+ case eRegNumARM_DWARF_s12_obsolete: case eRegNumARM_DWARF_s12: return "s12";
+ case eRegNumARM_DWARF_s13_obsolete: case eRegNumARM_DWARF_s13: return "s13";
+ case eRegNumARM_DWARF_s14_obsolete: case eRegNumARM_DWARF_s14: return "s14";
+ case eRegNumARM_DWARF_s15_obsolete: case eRegNumARM_DWARF_s15: return "s15";
+ case eRegNumARM_DWARF_s16_obsolete: case eRegNumARM_DWARF_s16: return "s16";
+ case eRegNumARM_DWARF_s17_obsolete: case eRegNumARM_DWARF_s17: return "s17";
+ case eRegNumARM_DWARF_s18_obsolete: case eRegNumARM_DWARF_s18: return "s18";
+ case eRegNumARM_DWARF_s19_obsolete: case eRegNumARM_DWARF_s19: return "s19";
+ case eRegNumARM_DWARF_s20_obsolete: case eRegNumARM_DWARF_s20: return "s20";
+ case eRegNumARM_DWARF_s21_obsolete: case eRegNumARM_DWARF_s21: return "s21";
+ case eRegNumARM_DWARF_s22_obsolete: case eRegNumARM_DWARF_s22: return "s22";
+ case eRegNumARM_DWARF_s23_obsolete: case eRegNumARM_DWARF_s23: return "s23";
+ case eRegNumARM_DWARF_s24_obsolete: case eRegNumARM_DWARF_s24: return "s24";
+ case eRegNumARM_DWARF_s25_obsolete: case eRegNumARM_DWARF_s25: return "s25";
+ case eRegNumARM_DWARF_s26_obsolete: case eRegNumARM_DWARF_s26: return "s26";
+ case eRegNumARM_DWARF_s27_obsolete: case eRegNumARM_DWARF_s27: return "s27";
+ case eRegNumARM_DWARF_s28_obsolete: case eRegNumARM_DWARF_s28: return "s28";
+ case eRegNumARM_DWARF_s29_obsolete: case eRegNumARM_DWARF_s29: return "s29";
+ case eRegNumARM_DWARF_s30_obsolete: case eRegNumARM_DWARF_s30: return "s30";
+ case eRegNumARM_DWARF_s31_obsolete: case eRegNumARM_DWARF_s31: return "s31";
+ case eRegNumARM_DWARF_f0: return "f0";
+ case eRegNumARM_DWARF_f1: return "f1";
+ case eRegNumARM_DWARF_f2: return "f2";
+ case eRegNumARM_DWARF_f3: return "f3";
+ case eRegNumARM_DWARF_f4: return "f4";
+ case eRegNumARM_DWARF_f5: return "f5";
+ case eRegNumARM_DWARF_f6: return "f6";
+ case eRegNumARM_DWARF_f7: return "f7";
+ case eRegNumARM_DWARF_wCGR0: return "wCGR0/ACC0";
+ case eRegNumARM_DWARF_wCGR1: return "wCGR1/ACC1";
+ case eRegNumARM_DWARF_wCGR2: return "wCGR2/ACC2";
+ case eRegNumARM_DWARF_wCGR3: return "wCGR3/ACC3";
+ case eRegNumARM_DWARF_wCGR4: return "wCGR4/ACC4";
+ case eRegNumARM_DWARF_wCGR5: return "wCGR5/ACC5";
+ case eRegNumARM_DWARF_wCGR6: return "wCGR6/ACC6";
+ case eRegNumARM_DWARF_wCGR7: return "wCGR7/ACC7";
+ case eRegNumARM_DWARF_wR0: return "wR0";
+ case eRegNumARM_DWARF_wR1: return "wR1";
+ case eRegNumARM_DWARF_wR2: return "wR2";
+ case eRegNumARM_DWARF_wR3: return "wR3";
+ case eRegNumARM_DWARF_wR4: return "wR4";
+ case eRegNumARM_DWARF_wR5: return "wR5";
+ case eRegNumARM_DWARF_wR6: return "wR6";
+ case eRegNumARM_DWARF_wR7: return "wR7";
+ case eRegNumARM_DWARF_wR8: return "wR8";
+ case eRegNumARM_DWARF_wR9: return "wR9";
+ case eRegNumARM_DWARF_wR10: return "wR10";
+ case eRegNumARM_DWARF_wR11: return "wR11";
+ case eRegNumARM_DWARF_wR12: return "wR12";
+ case eRegNumARM_DWARF_wR13: return "wR13";
+ case eRegNumARM_DWARF_wR14: return "wR14";
+ case eRegNumARM_DWARF_wR15: return "wR15";
+ case eRegNumARM_DWARF_spsr: return "spsr";
+ case eRegNumARM_DWARF_spsr_fiq: return "spsr_fiq";
+ case eRegNumARM_DWARF_spsr_irq: return "spsr_irq";
+ case eRegNumARM_DWARF_spsr_abt: return "spsr_abt";
+ case eRegNumARM_DWARF_spsr_und: return "spsr_und";
+ case eRegNumARM_DWARF_spsr_svc: return "spsr_svc";
+ case eRegNumARM_DWARF_r8_usr: return "r8_usr";
+ case eRegNumARM_DWARF_r9_usr: return "r9_usr";
+ case eRegNumARM_DWARF_r10_usr: return "r10_usr";
+ case eRegNumARM_DWARF_r11_usr: return "r11_usr";
+ case eRegNumARM_DWARF_r12_usr: return "r12_usr";
+ case eRegNumARM_DWARF_r13_usr: return "sp_usr";
+ case eRegNumARM_DWARF_r14_usr: return "lr_usr";
+ case eRegNumARM_DWARF_r8_fiq: return "r8_fiq";
+ case eRegNumARM_DWARF_r9_fiq: return "r9_fiq";
+ case eRegNumARM_DWARF_r10_fiq: return "r10_fiq";
+ case eRegNumARM_DWARF_r11_fiq: return "r11_fiq";
+ case eRegNumARM_DWARF_r12_fiq: return "r12_fiq";
+ case eRegNumARM_DWARF_r13_fiq: return "sp_fiq";
+ case eRegNumARM_DWARF_r14_fiq: return "lr_fiq";
+ case eRegNumARM_DWARF_r13_irq: return "sp_irq";
+ case eRegNumARM_DWARF_r14_irq: return "lr_irq";
+ case eRegNumARM_DWARF_r13_abt: return "sp_abt";
+ case eRegNumARM_DWARF_r14_abt: return "lr_abt";
+ case eRegNumARM_DWARF_r13_und: return "sp_und";
+ case eRegNumARM_DWARF_r14_und: return "lr_und";
+ case eRegNumARM_DWARF_r13_svc: return "sp_svc";
+ case eRegNumARM_DWARF_r14_svc: return "lr_svc";
+ case eRegNumARM_DWARF_wC0: return "wC0";
+ case eRegNumARM_DWARF_wC1: return "wC1";
+ case eRegNumARM_DWARF_wC2: return "wC2";
+ case eRegNumARM_DWARF_wC3: return "wC3";
+ case eRegNumARM_DWARF_wC4: return "wC4";
+ case eRegNumARM_DWARF_wC5: return "wC5";
+ case eRegNumARM_DWARF_wC6: return "wC6";
+ case eRegNumARM_DWARF_wC7: return "wC7";
+ case eRegNumARM_DWARF_d0: return "d0";
+ case eRegNumARM_DWARF_d1: return "d1";
+ case eRegNumARM_DWARF_d2: return "d2";
+ case eRegNumARM_DWARF_d3: return "d3";
+ case eRegNumARM_DWARF_d4: return "d4";
+ case eRegNumARM_DWARF_d5: return "d5";
+ case eRegNumARM_DWARF_d6: return "d6";
+ case eRegNumARM_DWARF_d7: return "d7";
+ case eRegNumARM_DWARF_d8: return "d8";
+ case eRegNumARM_DWARF_d9: return "d9";
+ case eRegNumARM_DWARF_d10: return "d10";
+ case eRegNumARM_DWARF_d11: return "d11";
+ case eRegNumARM_DWARF_d12: return "d12";
+ case eRegNumARM_DWARF_d13: return "d13";
+ case eRegNumARM_DWARF_d14: return "d14";
+ case eRegNumARM_DWARF_d15: return "d15";
+ case eRegNumARM_DWARF_d16: return "d16";
+ case eRegNumARM_DWARF_d17: return "d17";
+ case eRegNumARM_DWARF_d18: return "d18";
+ case eRegNumARM_DWARF_d19: return "d19";
+ case eRegNumARM_DWARF_d20: return "d20";
+ case eRegNumARM_DWARF_d21: return "d21";
+ case eRegNumARM_DWARF_d22: return "d22";
+ case eRegNumARM_DWARF_d23: return "d23";
+ case eRegNumARM_DWARF_d24: return "d24";
+ case eRegNumARM_DWARF_d25: return "d25";
+ case eRegNumARM_DWARF_d26: return "d26";
+ case eRegNumARM_DWARF_d27: return "d27";
+ case eRegNumARM_DWARF_d28: return "d28";
+ case eRegNumARM_DWARF_d29: return "d29";
+ case eRegNumARM_DWARF_d30: return "d30";
+ case eRegNumARM_DWARF_d31: return "d31";
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else if (cpu == CPU_TYPE_POWERPC || cpu == CPU_TYPE_POWERPC64)
+ {
+ switch (reg_kind)
+ {
+ case eRegisterKindGCC:
+ switch (reg_num)
+ {
+ case eRegNumPPC_GCC_r0: return "r0";
+ case eRegNumPPC_GCC_r1: return "r1";
+ case eRegNumPPC_GCC_r2: return "r2";
+ case eRegNumPPC_GCC_r3: return "r3";
+ case eRegNumPPC_GCC_r4: return "r4";
+ case eRegNumPPC_GCC_r5: return "r5";
+ case eRegNumPPC_GCC_r6: return "r6";
+ case eRegNumPPC_GCC_r7: return "r7";
+ case eRegNumPPC_GCC_r8: return "r8";
+ case eRegNumPPC_GCC_r9: return "r9";
+ case eRegNumPPC_GCC_r10: return "r10";
+ case eRegNumPPC_GCC_r11: return "r11";
+ case eRegNumPPC_GCC_r12: return "r12";
+ case eRegNumPPC_GCC_r13: return "r13";
+ case eRegNumPPC_GCC_r14: return "r14";
+ case eRegNumPPC_GCC_r15: return "r15";
+ case eRegNumPPC_GCC_r16: return "r16";
+ case eRegNumPPC_GCC_r17: return "r17";
+ case eRegNumPPC_GCC_r18: return "r18";
+ case eRegNumPPC_GCC_r19: return "r19";
+ case eRegNumPPC_GCC_r20: return "r20";
+ case eRegNumPPC_GCC_r21: return "r21";
+ case eRegNumPPC_GCC_r22: return "r22";
+ case eRegNumPPC_GCC_r23: return "r23";
+ case eRegNumPPC_GCC_r24: return "r24";
+ case eRegNumPPC_GCC_r25: return "r25";
+ case eRegNumPPC_GCC_r26: return "r26";
+ case eRegNumPPC_GCC_r27: return "r27";
+ case eRegNumPPC_GCC_r28: return "r28";
+ case eRegNumPPC_GCC_r29: return "r29";
+ case eRegNumPPC_GCC_r30: return "r30";
+ case eRegNumPPC_GCC_r31: return "r31";
+ case eRegNumPPC_GCC_fr0: return "fr0";
+ case eRegNumPPC_GCC_fr1: return "fr1";
+ case eRegNumPPC_GCC_fr2: return "fr2";
+ case eRegNumPPC_GCC_fr3: return "fr3";
+ case eRegNumPPC_GCC_fr4: return "fr4";
+ case eRegNumPPC_GCC_fr5: return "fr5";
+ case eRegNumPPC_GCC_fr6: return "fr6";
+ case eRegNumPPC_GCC_fr7: return "fr7";
+ case eRegNumPPC_GCC_fr8: return "fr8";
+ case eRegNumPPC_GCC_fr9: return "fr9";
+ case eRegNumPPC_GCC_fr10: return "fr10";
+ case eRegNumPPC_GCC_fr11: return "fr11";
+ case eRegNumPPC_GCC_fr12: return "fr12";
+ case eRegNumPPC_GCC_fr13: return "fr13";
+ case eRegNumPPC_GCC_fr14: return "fr14";
+ case eRegNumPPC_GCC_fr15: return "fr15";
+ case eRegNumPPC_GCC_fr16: return "fr16";
+ case eRegNumPPC_GCC_fr17: return "fr17";
+ case eRegNumPPC_GCC_fr18: return "fr18";
+ case eRegNumPPC_GCC_fr19: return "fr19";
+ case eRegNumPPC_GCC_fr20: return "fr20";
+ case eRegNumPPC_GCC_fr21: return "fr21";
+ case eRegNumPPC_GCC_fr22: return "fr22";
+ case eRegNumPPC_GCC_fr23: return "fr23";
+ case eRegNumPPC_GCC_fr24: return "fr24";
+ case eRegNumPPC_GCC_fr25: return "fr25";
+ case eRegNumPPC_GCC_fr26: return "fr26";
+ case eRegNumPPC_GCC_fr27: return "fr27";
+ case eRegNumPPC_GCC_fr28: return "fr28";
+ case eRegNumPPC_GCC_fr29: return "fr29";
+ case eRegNumPPC_GCC_fr30: return "fr30";
+ case eRegNumPPC_GCC_fr31: return "fr31";
+ case eRegNumPPC_GCC_mq: return "mq";
+ case eRegNumPPC_GCC_lr: return "lr";
+ case eRegNumPPC_GCC_ctr: return "ctr";
+ case eRegNumPPC_GCC_ap: return "ap";
+ case eRegNumPPC_GCC_cr0: return "cr0";
+ case eRegNumPPC_GCC_cr1: return "cr1";
+ case eRegNumPPC_GCC_cr2: return "cr2";
+ case eRegNumPPC_GCC_cr3: return "cr3";
+ case eRegNumPPC_GCC_cr4: return "cr4";
+ case eRegNumPPC_GCC_cr5: return "cr5";
+ case eRegNumPPC_GCC_cr6: return "cr6";
+ case eRegNumPPC_GCC_cr7: return "cr7";
+ case eRegNumPPC_GCC_xer: return "xer";
+ case eRegNumPPC_GCC_v0: return "v0";
+ case eRegNumPPC_GCC_v1: return "v1";
+ case eRegNumPPC_GCC_v2: return "v2";
+ case eRegNumPPC_GCC_v3: return "v3";
+ case eRegNumPPC_GCC_v4: return "v4";
+ case eRegNumPPC_GCC_v5: return "v5";
+ case eRegNumPPC_GCC_v6: return "v6";
+ case eRegNumPPC_GCC_v7: return "v7";
+ case eRegNumPPC_GCC_v8: return "v8";
+ case eRegNumPPC_GCC_v9: return "v9";
+ case eRegNumPPC_GCC_v10: return "v10";
+ case eRegNumPPC_GCC_v11: return "v11";
+ case eRegNumPPC_GCC_v12: return "v12";
+ case eRegNumPPC_GCC_v13: return "v13";
+ case eRegNumPPC_GCC_v14: return "v14";
+ case eRegNumPPC_GCC_v15: return "v15";
+ case eRegNumPPC_GCC_v16: return "v16";
+ case eRegNumPPC_GCC_v17: return "v17";
+ case eRegNumPPC_GCC_v18: return "v18";
+ case eRegNumPPC_GCC_v19: return "v19";
+ case eRegNumPPC_GCC_v20: return "v20";
+ case eRegNumPPC_GCC_v21: return "v21";
+ case eRegNumPPC_GCC_v22: return "v22";
+ case eRegNumPPC_GCC_v23: return "v23";
+ case eRegNumPPC_GCC_v24: return "v24";
+ case eRegNumPPC_GCC_v25: return "v25";
+ case eRegNumPPC_GCC_v26: return "v26";
+ case eRegNumPPC_GCC_v27: return "v27";
+ case eRegNumPPC_GCC_v28: return "v28";
+ case eRegNumPPC_GCC_v29: return "v29";
+ case eRegNumPPC_GCC_v30: return "v30";
+ case eRegNumPPC_GCC_v31: return "v31";
+ case eRegNumPPC_GCC_vrsave: return "vrsave";
+ case eRegNumPPC_GCC_vscr: return "vscr";
+ case eRegNumPPC_GCC_spe_acc: return "spe_acc";
+ case eRegNumPPC_GCC_spefscr: return "spefscr";
+ case eRegNumPPC_GCC_sfp: return "sfp";
+ default:
+ break;
+ }
+ break;
+
+ case eRegisterKindDWARF:
+ switch (reg_num)
+ {
+ case eRegNumPPC_DWARF_r0: return "r0";
+ case eRegNumPPC_DWARF_r1: return "r1";
+ case eRegNumPPC_DWARF_r2: return "r2";
+ case eRegNumPPC_DWARF_r3: return "r3";
+ case eRegNumPPC_DWARF_r4: return "r4";
+ case eRegNumPPC_DWARF_r5: return "r5";
+ case eRegNumPPC_DWARF_r6: return "r6";
+ case eRegNumPPC_DWARF_r7: return "r7";
+ case eRegNumPPC_DWARF_r8: return "r8";
+ case eRegNumPPC_DWARF_r9: return "r9";
+ case eRegNumPPC_DWARF_r10: return "r10";
+ case eRegNumPPC_DWARF_r11: return "r11";
+ case eRegNumPPC_DWARF_r12: return "r12";
+ case eRegNumPPC_DWARF_r13: return "r13";
+ case eRegNumPPC_DWARF_r14: return "r14";
+ case eRegNumPPC_DWARF_r15: return "r15";
+ case eRegNumPPC_DWARF_r16: return "r16";
+ case eRegNumPPC_DWARF_r17: return "r17";
+ case eRegNumPPC_DWARF_r18: return "r18";
+ case eRegNumPPC_DWARF_r19: return "r19";
+ case eRegNumPPC_DWARF_r20: return "r20";
+ case eRegNumPPC_DWARF_r21: return "r21";
+ case eRegNumPPC_DWARF_r22: return "r22";
+ case eRegNumPPC_DWARF_r23: return "r23";
+ case eRegNumPPC_DWARF_r24: return "r24";
+ case eRegNumPPC_DWARF_r25: return "r25";
+ case eRegNumPPC_DWARF_r26: return "r26";
+ case eRegNumPPC_DWARF_r27: return "r27";
+ case eRegNumPPC_DWARF_r28: return "r28";
+ case eRegNumPPC_DWARF_r29: return "r29";
+ case eRegNumPPC_DWARF_r30: return "r30";
+ case eRegNumPPC_DWARF_r31: return "r31";
+
+ case eRegNumPPC_DWARF_fr0: return "fr0";
+ case eRegNumPPC_DWARF_fr1: return "fr1";
+ case eRegNumPPC_DWARF_fr2: return "fr2";
+ case eRegNumPPC_DWARF_fr3: return "fr3";
+ case eRegNumPPC_DWARF_fr4: return "fr4";
+ case eRegNumPPC_DWARF_fr5: return "fr5";
+ case eRegNumPPC_DWARF_fr6: return "fr6";
+ case eRegNumPPC_DWARF_fr7: return "fr7";
+ case eRegNumPPC_DWARF_fr8: return "fr8";
+ case eRegNumPPC_DWARF_fr9: return "fr9";
+ case eRegNumPPC_DWARF_fr10: return "fr10";
+ case eRegNumPPC_DWARF_fr11: return "fr11";
+ case eRegNumPPC_DWARF_fr12: return "fr12";
+ case eRegNumPPC_DWARF_fr13: return "fr13";
+ case eRegNumPPC_DWARF_fr14: return "fr14";
+ case eRegNumPPC_DWARF_fr15: return "fr15";
+ case eRegNumPPC_DWARF_fr16: return "fr16";
+ case eRegNumPPC_DWARF_fr17: return "fr17";
+ case eRegNumPPC_DWARF_fr18: return "fr18";
+ case eRegNumPPC_DWARF_fr19: return "fr19";
+ case eRegNumPPC_DWARF_fr20: return "fr20";
+ case eRegNumPPC_DWARF_fr21: return "fr21";
+ case eRegNumPPC_DWARF_fr22: return "fr22";
+ case eRegNumPPC_DWARF_fr23: return "fr23";
+ case eRegNumPPC_DWARF_fr24: return "fr24";
+ case eRegNumPPC_DWARF_fr25: return "fr25";
+ case eRegNumPPC_DWARF_fr26: return "fr26";
+ case eRegNumPPC_DWARF_fr27: return "fr27";
+ case eRegNumPPC_DWARF_fr28: return "fr28";
+ case eRegNumPPC_DWARF_fr29: return "fr29";
+ case eRegNumPPC_DWARF_fr30: return "fr30";
+ case eRegNumPPC_DWARF_fr31: return "fr31";
+
+ case eRegNumPPC_DWARF_cr: return "cr";
+ case eRegNumPPC_DWARF_fpscr: return "fpscr";
+ case eRegNumPPC_DWARF_msr: return "msr";
+ case eRegNumPPC_DWARF_vscr: return "vscr";
+
+ case eRegNumPPC_DWARF_sr0: return "sr0";
+ case eRegNumPPC_DWARF_sr1: return "sr1";
+ case eRegNumPPC_DWARF_sr2: return "sr2";
+ case eRegNumPPC_DWARF_sr3: return "sr3";
+ case eRegNumPPC_DWARF_sr4: return "sr4";
+ case eRegNumPPC_DWARF_sr5: return "sr5";
+ case eRegNumPPC_DWARF_sr6: return "sr6";
+ case eRegNumPPC_DWARF_sr7: return "sr7";
+ case eRegNumPPC_DWARF_sr8: return "sr8";
+ case eRegNumPPC_DWARF_sr9: return "sr9";
+ case eRegNumPPC_DWARF_sr10: return "sr10";
+ case eRegNumPPC_DWARF_sr11: return "sr11";
+ case eRegNumPPC_DWARF_sr12: return "sr12";
+ case eRegNumPPC_DWARF_sr13: return "sr13";
+ case eRegNumPPC_DWARF_sr14: return "sr14";
+ case eRegNumPPC_DWARF_sr15: return "sr15";
+
+ case eRegNumPPC_DWARF_acc: return "acc";
+ case eRegNumPPC_DWARF_mq: return "mq";
+ case eRegNumPPC_DWARF_xer: return "xer";
+ case eRegNumPPC_DWARF_rtcu: return "rtcu";
+ case eRegNumPPC_DWARF_rtcl: return "rtcl";
+
+ case eRegNumPPC_DWARF_lr: return "lr";
+ case eRegNumPPC_DWARF_ctr: return "ctr";
+
+ case eRegNumPPC_DWARF_dsisr: return "dsisr";
+ case eRegNumPPC_DWARF_dar: return "dar";
+ case eRegNumPPC_DWARF_dec: return "dec";
+ case eRegNumPPC_DWARF_sdr1: return "sdr1";
+ case eRegNumPPC_DWARF_srr0: return "srr0";
+ case eRegNumPPC_DWARF_srr1: return "srr1";
+
+ case eRegNumPPC_DWARF_vrsave: return "vrsave";
+
+ case eRegNumPPC_DWARF_sprg0: return "sprg0";
+ case eRegNumPPC_DWARF_sprg1: return "sprg1";
+ case eRegNumPPC_DWARF_sprg2: return "sprg2";
+ case eRegNumPPC_DWARF_sprg3: return "sprg3";
+
+ case eRegNumPPC_DWARF_asr: return "asr";
+ case eRegNumPPC_DWARF_ear: return "ear";
+ case eRegNumPPC_DWARF_tb: return "tb";
+ case eRegNumPPC_DWARF_tbu: return "tbu";
+ case eRegNumPPC_DWARF_pvr: return "pvr";
+
+ case eRegNumPPC_DWARF_spefscr: return "spefscr";
+
+ case eRegNumPPC_DWARF_ibat0u: return "ibat0u";
+ case eRegNumPPC_DWARF_ibat0l: return "ibat0l";
+ case eRegNumPPC_DWARF_ibat1u: return "ibat1u";
+ case eRegNumPPC_DWARF_ibat1l: return "ibat1l";
+ case eRegNumPPC_DWARF_ibat2u: return "ibat2u";
+ case eRegNumPPC_DWARF_ibat2l: return "ibat2l";
+ case eRegNumPPC_DWARF_ibat3u: return "ibat3u";
+ case eRegNumPPC_DWARF_ibat3l: return "ibat3l";
+ case eRegNumPPC_DWARF_dbat0u: return "dbat0u";
+ case eRegNumPPC_DWARF_dbat0l: return "dbat0l";
+ case eRegNumPPC_DWARF_dbat1u: return "dbat1u";
+ case eRegNumPPC_DWARF_dbat1l: return "dbat1l";
+ case eRegNumPPC_DWARF_dbat2u: return "dbat2u";
+ case eRegNumPPC_DWARF_dbat2l: return "dbat2l";
+ case eRegNumPPC_DWARF_dbat3u: return "dbat3u";
+ case eRegNumPPC_DWARF_dbat3l: return "dbat3l";
+
+ case eRegNumPPC_DWARF_hid0: return "hid0";
+ case eRegNumPPC_DWARF_hid1: return "hid1";
+ case eRegNumPPC_DWARF_hid2: return "hid2";
+ case eRegNumPPC_DWARF_hid3: return "hid3";
+ case eRegNumPPC_DWARF_hid4: return "hid4";
+ case eRegNumPPC_DWARF_hid5: return "hid5";
+ case eRegNumPPC_DWARF_hid6: return "hid6";
+ case eRegNumPPC_DWARF_hid7: return "hid7";
+ case eRegNumPPC_DWARF_hid8: return "hid8";
+ case eRegNumPPC_DWARF_hid9: return "hid9";
+ case eRegNumPPC_DWARF_hid10: return "hid10";
+ case eRegNumPPC_DWARF_hid11: return "hid11";
+ case eRegNumPPC_DWARF_hid12: return "hid12";
+ case eRegNumPPC_DWARF_hid13: return "hid13";
+ case eRegNumPPC_DWARF_hid14: return "hid14";
+ case eRegNumPPC_DWARF_hid15: return "hid15";
+
+ case eRegNumPPC_DWARF_vr0: return "vr0";
+ case eRegNumPPC_DWARF_vr1: return "vr1";
+ case eRegNumPPC_DWARF_vr2: return "vr2";
+ case eRegNumPPC_DWARF_vr3: return "vr3";
+ case eRegNumPPC_DWARF_vr4: return "vr4";
+ case eRegNumPPC_DWARF_vr5: return "vr5";
+ case eRegNumPPC_DWARF_vr6: return "vr6";
+ case eRegNumPPC_DWARF_vr7: return "vr7";
+ case eRegNumPPC_DWARF_vr8: return "vr8";
+ case eRegNumPPC_DWARF_vr9: return "vr9";
+ case eRegNumPPC_DWARF_vr10: return "vr10";
+ case eRegNumPPC_DWARF_vr11: return "vr11";
+ case eRegNumPPC_DWARF_vr12: return "vr12";
+ case eRegNumPPC_DWARF_vr13: return "vr13";
+ case eRegNumPPC_DWARF_vr14: return "vr14";
+ case eRegNumPPC_DWARF_vr15: return "vr15";
+ case eRegNumPPC_DWARF_vr16: return "vr16";
+ case eRegNumPPC_DWARF_vr17: return "vr17";
+ case eRegNumPPC_DWARF_vr18: return "vr18";
+ case eRegNumPPC_DWARF_vr19: return "vr19";
+ case eRegNumPPC_DWARF_vr20: return "vr20";
+ case eRegNumPPC_DWARF_vr21: return "vr21";
+ case eRegNumPPC_DWARF_vr22: return "vr22";
+ case eRegNumPPC_DWARF_vr23: return "vr23";
+ case eRegNumPPC_DWARF_vr24: return "vr24";
+ case eRegNumPPC_DWARF_vr25: return "vr25";
+ case eRegNumPPC_DWARF_vr26: return "vr26";
+ case eRegNumPPC_DWARF_vr27: return "vr27";
+ case eRegNumPPC_DWARF_vr28: return "vr28";
+ case eRegNumPPC_DWARF_vr29: return "vr29";
+ case eRegNumPPC_DWARF_vr30: return "vr30";
+ case eRegNumPPC_DWARF_vr31: return "vr31";
+
+ case eRegNumPPC_DWARF_ev0: return "ev0";
+ case eRegNumPPC_DWARF_ev1: return "ev1";
+ case eRegNumPPC_DWARF_ev2: return "ev2";
+ case eRegNumPPC_DWARF_ev3: return "ev3";
+ case eRegNumPPC_DWARF_ev4: return "ev4";
+ case eRegNumPPC_DWARF_ev5: return "ev5";
+ case eRegNumPPC_DWARF_ev6: return "ev6";
+ case eRegNumPPC_DWARF_ev7: return "ev7";
+ case eRegNumPPC_DWARF_ev8: return "ev8";
+ case eRegNumPPC_DWARF_ev9: return "ev9";
+ case eRegNumPPC_DWARF_ev10: return "ev10";
+ case eRegNumPPC_DWARF_ev11: return "ev11";
+ case eRegNumPPC_DWARF_ev12: return "ev12";
+ case eRegNumPPC_DWARF_ev13: return "ev13";
+ case eRegNumPPC_DWARF_ev14: return "ev14";
+ case eRegNumPPC_DWARF_ev15: return "ev15";
+ case eRegNumPPC_DWARF_ev16: return "ev16";
+ case eRegNumPPC_DWARF_ev17: return "ev17";
+ case eRegNumPPC_DWARF_ev18: return "ev18";
+ case eRegNumPPC_DWARF_ev19: return "ev19";
+ case eRegNumPPC_DWARF_ev20: return "ev20";
+ case eRegNumPPC_DWARF_ev21: return "ev21";
+ case eRegNumPPC_DWARF_ev22: return "ev22";
+ case eRegNumPPC_DWARF_ev23: return "ev23";
+ case eRegNumPPC_DWARF_ev24: return "ev24";
+ case eRegNumPPC_DWARF_ev25: return "ev25";
+ case eRegNumPPC_DWARF_ev26: return "ev26";
+ case eRegNumPPC_DWARF_ev27: return "ev27";
+ case eRegNumPPC_DWARF_ev28: return "ev28";
+ case eRegNumPPC_DWARF_ev29: return "ev29";
+ case eRegNumPPC_DWARF_ev30: return "ev30";
+ case eRegNumPPC_DWARF_ev31: return "ev31";
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Returns true if this object contains a valid architecture, false
+// otherwise.
+//----------------------------------------------------------------------
+bool
+ArchSpec::IsValid() const
+{
+ return !(m_cpu == LLDB_INVALID_CPUTYPE);
+}
+
+//----------------------------------------------------------------------
+// Returns true if this architecture is 64 bit, otherwise 32 bit is
+// assumed and false is returned.
+//----------------------------------------------------------------------
+uint32_t
+ArchSpec::GetAddressByteSize() const
+{
+ if (GetCPUType() & CPU_ARCH_ABI64)
+ return 8;
+ return 4;
+}
+
+//----------------------------------------------------------------------
+// Returns the number of bytes that this object takes when an
+// instance exists in memory.
+//----------------------------------------------------------------------
+size_t
+ArchSpec::MemorySize() const
+{
+ return sizeof(ArchSpec);
+}
+
+bool
+ArchSpec::SetArchFromTargetTriple (const char *target_triple)
+{
+ if (target_triple)
+ {
+ const char *hyphen = strchr(target_triple, '-');
+ if (hyphen)
+ {
+ std::string arch_only (target_triple, hyphen);
+ return SetArch (arch_only.c_str());
+ }
+ }
+ return SetArch (target_triple);
+}
+
+//----------------------------------------------------------------------
+// Change the CPU type and subtype given an architecture name.
+//----------------------------------------------------------------------
+bool
+ArchSpec::SetArch(const char *arch_name)
+{
+ if (arch_name && arch_name[0] != '\0')
+ {
+ size_t i;
+ // Search for ARCH_NAME in our architecture definitions structure
+ for (i=0; i<k_num_arch_defs; ++i)
+ {
+ if (strcasecmp(arch_name, g_arch_defs[i].name) == 0)
+ {
+ // we found a match
+ m_cpu = g_arch_defs[i].cpu;
+ m_sub = g_arch_defs[i].sub;
+ return true;
+ }
+ }
+
+
+ const char *str = arch_name;
+ char *end = NULL;
+ // Check for a numeric cpu followed by an optional '.' and numeric subtype.
+ // This allows for support of new cpu type/subtypes without having to have
+ // a recompiled debug core.
+ // Examples:
+ // "12.6" is armv6
+ // "0x0000000c.0x00000006" is also armv6
+ m_cpu = strtoul(str, &end, 0);
+ if (str != end)
+ {
+ if (*end == '.')
+ {
+ // We have a cputype.cpusubtype format
+ str = end + 1;
+ if (*str != '\0')
+ {
+ m_sub = strtoul(str, &end, 0);
+ if (*end == '\0')
+ {
+ // We consumed the entire string and got a cpu type and subtype
+ return true;
+ }
+ }
+ }
+
+ // If we reach this point we have a valid cpu type, but no cpu subtype.
+ // Search for the first matching cpu type and use the corresponding cpu
+ // subtype. This setting should typically be the _ALL variant and should
+ // appear first in the list for each cpu type in the g_arch_defs
+ // structure.
+ for (i=0; i<k_num_arch_defs; ++i)
+ {
+ if (m_cpu == g_arch_defs[i].cpu)
+ {
+ m_sub = g_arch_defs[i].sub;
+ return true;
+ }
+ }
+
+ // Default the cpu subtype to zero when we don't have a matching
+ // cpu type in our architecture defs structure (g_arch_defs).
+ m_sub = 0;
+ return true;
+
+ }
+ }
+ m_cpu = LLDB_INVALID_CPUTYPE;
+ m_sub = 0;
+ return false;
+}
+
+//----------------------------------------------------------------------
+// CPU type and subtype set accessor.
+//----------------------------------------------------------------------
+void
+ArchSpec::SetArch (uint32_t cpu_type, uint32_t cpu_subtype)
+{
+ m_cpu = cpu_type;
+ m_sub = cpu_subtype;
+}
+
+//----------------------------------------------------------------------
+// CPU type set accessor.
+//----------------------------------------------------------------------
+void
+ArchSpec::SetCPUType (uint32_t cpu)
+{
+ m_cpu = cpu;
+}
+
+//----------------------------------------------------------------------
+// CPU subtype set accessor.
+//----------------------------------------------------------------------
+void
+ArchSpec::SetCPUSubtype (uint32_t subtype)
+{
+ m_sub = subtype;
+}
+
+ByteOrder
+ArchSpec::GetDefaultEndian () const
+{
+ switch (m_cpu)
+ {
+ case CPU_TYPE_POWERPC:
+ case CPU_TYPE_POWERPC64:
+ return eByteOrderBig;
+
+ case CPU_TYPE_ARM:
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ return eByteOrderLittle;
+
+ default:
+ break;
+ }
+ return eByteOrderInvalid;
+}
+
+//----------------------------------------------------------------------
+// Equal operator
+//----------------------------------------------------------------------
+bool
+lldb_private::operator== (const ArchSpec& lhs, const ArchSpec& rhs)
+{
+ uint32_t lhs_cpu = lhs.GetCPUType();
+ uint32_t rhs_cpu = rhs.GetCPUType();
+
+ if (lhs_cpu == CPU_TYPE_ANY || rhs_cpu == CPU_TYPE_ANY)
+ return true;
+
+ else if (lhs_cpu == rhs_cpu)
+ {
+ uint32_t lhs_subtype = lhs.GetCPUSubtype();
+ uint32_t rhs_subtype = rhs.GetCPUSubtype();
+ if (lhs_subtype == CPU_TYPE_ANY || rhs_subtype == CPU_TYPE_ANY)
+ return true;
+ return lhs_subtype == rhs_subtype;
+ }
+ return false;
+}
+
+
+//----------------------------------------------------------------------
+// Not Equal operator
+//----------------------------------------------------------------------
+bool
+lldb_private::operator!= (const ArchSpec& lhs, const ArchSpec& rhs)
+{
+ return !(lhs == rhs);
+}
+
+//----------------------------------------------------------------------
+// Less than operator
+//----------------------------------------------------------------------
+bool
+lldb_private::operator<(const ArchSpec& lhs, const ArchSpec& rhs)
+{
+ uint32_t lhs_cpu = lhs.GetCPUType();
+ uint32_t rhs_cpu = rhs.GetCPUType();
+
+ if (lhs_cpu == rhs_cpu)
+ return lhs.GetCPUSubtype() < rhs.GetCPUSubtype();
+
+ return lhs_cpu < rhs_cpu;
+}
+
diff --git a/lldb/source/Core/Args.cpp b/lldb/source/Core/Args.cpp
new file mode 100644
index 00000000000..7cb137555d1
--- /dev/null
+++ b/lldb/source/Core/Args.cpp
@@ -0,0 +1,1179 @@
+//===-- Args.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 <getopt.h>
+#include <histedit.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+namespace lldb_private {
+
+class Tokenizer
+{
+public:
+ Tokenizer (const char *separator_chars = NULL) :
+ m_tokenizer(NULL)
+ {
+ m_tokenizer = ::tok_init (separator_chars);
+ }
+
+ ~Tokenizer ()
+ {
+ if (m_tokenizer)
+ {
+ ::tok_end (m_tokenizer);
+ m_tokenizer = NULL;
+ }
+ }
+
+ void
+ Reset ()
+ {
+ assert (m_tokenizer);
+ ::tok_reset (m_tokenizer);
+ }
+
+ int
+ TokenizeLineInfo (const ::LineInfo *line_info)
+ {
+ assert (m_tokenizer);
+ return ::tok_line (m_tokenizer,
+ line_info,
+ &m_argc,
+ &m_argv,
+ &m_cursor_arg_index,
+ &m_cursor_arg_offset);
+ }
+
+ int
+ TokenizeCString (const char *cstr)
+ {
+ assert (m_tokenizer);
+ m_cursor_arg_index = -1;
+ m_cursor_arg_offset = -1;
+ return ::tok_str (m_tokenizer,
+ cstr,
+ &m_argc,
+ &m_argv);
+ }
+
+
+ int
+ GetArgCount () const
+ {
+ return m_argc;
+ }
+
+ const char **
+ GetArgVector () const
+ {
+ return m_argv;
+ }
+
+ int
+ GetCursoreArgIndex () const
+ {
+ return m_cursor_arg_index;
+ }
+
+ int
+ GetCursoreArgOffset () const
+ {
+ return m_cursor_arg_offset;
+ }
+
+
+protected:
+ struct tokenizer* m_tokenizer;
+ const char **m_argv;
+ int m_argc;
+ int m_cursor_arg_index;
+ int m_cursor_arg_offset;
+};
+
+} // namespace lldb_private
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const char *k_space_characters = "\t\n\v\f\r ";
+static const char *k_space_characters_with_slash = "\t\n\v\f\r \\";
+
+
+//----------------------------------------------------------------------
+// Args constructor
+//----------------------------------------------------------------------
+Args::Args (const char *command) :
+ m_args(),
+ m_argv()
+{
+ SetCommandString (command);
+}
+
+
+Args::Args (const char *command, size_t len) :
+ m_args(),
+ m_argv()
+{
+ SetCommandString (command, len);
+}
+
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Args::~Args ()
+{
+}
+
+void
+Args::Dump (Stream *s)
+{
+// int argc = GetArgumentCount();
+//
+// arg_sstr_collection::const_iterator pos, begin = m_args.begin(), end = m_args.end();
+// for (pos = m_args.begin(); pos != end; ++pos)
+// {
+// s->Indent();
+// s->Printf("args[%zu]=%s\n", std::distance(begin, pos), pos->c_str());
+// }
+// s->EOL();
+ const int argc = m_argv.size();
+ for (int i=0; i<argc; ++i)
+ {
+ s->Indent();
+ const char *arg_cstr = m_argv[i];
+ if (arg_cstr)
+ s->Printf("argv[%i]=\"%s\"\n", i, arg_cstr);
+ else
+ s->Printf("argv[%i]=NULL\n", i);
+ }
+ s->EOL();
+}
+
+bool
+Args::GetCommandString (std::string &command)
+{
+ command.clear();
+ int argc = GetArgumentCount();
+ for (int i=0; i<argc; ++i)
+ {
+ if (i > 0)
+ command += ' ';
+ command += 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();
+ if (command && command[0])
+ {
+ const char *arg_start;
+ const char *next_arg_start;
+ for (arg_start = command, next_arg_start = NULL;
+ arg_start && arg_start[0];
+ arg_start = next_arg_start, next_arg_start = NULL)
+ {
+ // Skip any leading space characters
+ arg_start = ::strspn (arg_start, k_space_characters) + arg_start;
+
+ // If there were only space characters to the end of the line, then
+ // we're done.
+ if (*arg_start == '\0')
+ break;
+
+ std::string arg;
+ const char *arg_end = NULL;
+
+ switch (*arg_start)
+ {
+ case '\'':
+ case '"':
+ case '`':
+ {
+ // Look for either a quote character, or the backslash
+ // character
+ const char quote_char = *arg_start;
+ char find_chars[3] = { quote_char, '\\' , '\0'};
+ bool is_backtick = (quote_char == '`');
+ if (quote_char == '"' || quote_char == '`')
+ m_args_quote_char.push_back(quote_char);
+ else
+ m_args_quote_char.push_back('\0');
+
+ while (*arg_start != '\0')
+ {
+ arg_end = ::strcspn (arg_start + 1, find_chars) + arg_start + 1;
+
+ if (*arg_end == '\0')
+ {
+ arg.append (arg_start);
+ break;
+ }
+
+ // Watch out for quote characters prefixed with '\'
+ if (*arg_end == '\\')
+ {
+ if (arg_end[1] == quote_char)
+ {
+ // The character following the '\' is our quote
+ // character so strip the backslash character
+ arg.append (arg_start, arg_end);
+ }
+ else
+ {
+ // The character following the '\' is NOT our
+ // quote character, so include the backslash
+ // and continue
+ arg.append (arg_start, arg_end + 1);
+ }
+ arg_start = arg_end + 1;
+ continue;
+ }
+ else
+ {
+ arg.append (arg_start, arg_end + 1);
+ next_arg_start = arg_end + 1;
+ break;
+ }
+ }
+
+ // Skip single and double quotes, but leave backtick quotes
+ if (!is_backtick)
+ {
+ char first_c = arg[0];
+ arg.erase(0,1);
+ // Only erase the last character if it is the same as the first.
+ // Otherwise, we're parsing an incomplete command line, and we
+ // would be stripping off the last character of that string.
+ if (arg[arg.size() - 1] == first_c)
+ arg.erase(arg.size() - 1, 1);
+ }
+ }
+ break;
+ default:
+ {
+ m_args_quote_char.push_back('\0');
+ // Look for the next non-escaped space character
+ while (*arg_start != '\0')
+ {
+ arg_end = ::strcspn (arg_start, k_space_characters_with_slash) + arg_start;
+
+ if (arg_end == NULL)
+ {
+ arg.append(arg_start);
+ break;
+ }
+
+ if (*arg_end == '\\')
+ {
+ // Append up to the '\' char
+ arg.append (arg_start, arg_end);
+
+ if (arg_end[1] == '\0')
+ break;
+
+ // Append the character following the '\' if it isn't
+ // the end of the string
+ arg.append (1, arg_end[1]);
+ arg_start = arg_end + 2;
+ continue;
+ }
+ else
+ {
+ arg.append (arg_start, arg_end);
+ next_arg_start = arg_end;
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ m_args.push_back(arg);
+ }
+ }
+ 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);
+}
+
+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();
+ 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));
+}
+
+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);
+
+
+ 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();
+ 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);
+ m_args_quote_char.erase(m_args_quote_char.begin() + idx);
+ }
+}
+
+void
+Args::SetArguments (int 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();
+
+ // Make a copy of the arguments in our internal buffer
+ size_t i;
+ // First copy each string
+ for (i=0; i<argc; ++i)
+ {
+ m_args.push_back (argv[i]);
+ if ((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;
+ int i;
+ Error error;
+ struct option *long_options = options.GetLongOptions();
+ if (long_options == NULL)
+ {
+ error.SetErrorStringWithFormat("Invalid long options.\n");
+ return error;
+ }
+
+ 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;
+ }
+ }
+ }
+ optreset = 1;
+ optind = 1;
+ int val;
+ while (1)
+ {
+ int long_options_index = -1;
+ val = ::getopt_long(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.\n");
+ 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'.\n", 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;
+ int32_t uval = ::strtol (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;
+}
+
+uint32_t
+Args::StringToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ char *end = NULL;
+ uint32_t uval = ::strtoul (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;
+}
+
+
+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 char *s, lldb::addr_t fail_value, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ char *end = NULL;
+ lldb::addr_t addr = ::strtoull (s, &end, 0);
+ if (*end == '\0')
+ {
+ if (success_ptr) *success_ptr = true;
+ return addr; // All characters were used, return the result
+ }
+ // Try base 16 with no prefix...
+ addr = ::strtoull (s, &end, 16);
+ if (*end == '\0')
+ {
+ if (success_ptr) *success_ptr = true;
+ return addr; // All characters were used, return the result
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+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;
+}
+
+int32_t
+Args::StringToOptionEnum (const char *s, lldb::OptionEnumValueElement *enum_values, int32_t fail_value, bool *success_ptr)
+{
+ if (enum_values && 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)
+ {
+ if (success_ptr) *success_ptr = true;
+ return enum_values[i].value;
+ }
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+
+ 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
+)
+{
+ format = eFormatInvalid;
+ Error error;
+
+ if (s && s[0])
+ {
+ switch (s[0])
+ {
+ case 'y': format = eFormatBytes; break;
+ case 'Y': format = eFormatBytesWithASCII; break;
+ case 'b': format = eFormatBinary; break;
+ case 'B': format = eFormatBoolean; break;
+ case 'c': format = eFormatChar; break;
+ case 'C': format = eFormatCharPrintable; break;
+ case 'o': format = eFormatOctal; break;
+ case 'i':
+ case 'd': format = eFormatDecimal; break;
+ case 'u': format = eFormatUnsigned; break;
+ case 'x': format = eFormatHex; break;
+ case 'f':
+ case 'e':
+ case 'g': format = eFormatFloat; break;
+ case 'p': format = eFormatPointer; break;
+ case 's': format = eFormatCString; break;
+ default:
+ error.SetErrorStringWithFormat("Invalid format character '%c'. Valid values are:\n"
+ " b - binary\n"
+ " B - boolean\n"
+ " c - char\n"
+ " C - printable char\n"
+ " d - signed decimal\n"
+ " e - float\n"
+ " f - float\n"
+ " g - float\n"
+ " i - signed decimal\n"
+ " o - octal\n"
+ " s - c-string\n"
+ " u - unsigned decimal\n"
+ " x - hex\n"
+ " y - bytes\n"
+ " Y - bytes with ASCII\n", s[0]);
+ break;
+ }
+
+ if (error.Fail())
+ return error;
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("%s option string.\n", s ? "empty" : "invalid");
+ }
+ return error;
+}
+
+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)
+ {
+ int 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 (int 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;
+ }
+}
+
+void
+Args::ParseAliasOptions
+(
+ Options &options,
+ CommandReturnObject &result,
+ OptionArgVector *option_arg_vector
+)
+{
+ 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;
+ }
+ }
+ }
+
+ optreset = 1;
+ optind = 1;
+ int val;
+ while (1)
+ {
+ int long_options_index = -1;
+ val = ::getopt_long (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", (char) val);
+
+ switch (long_options[long_options_index].has_arg)
+ {
+ case no_argument:
+ option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), "<no-argument>"));
+ break;
+ case required_argument:
+ if (optarg != NULL)
+ {
+ option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
+ 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()),
+ std::string (optarg)));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
+ "<no-argument>"));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ break;
+ default:
+ result.AppendErrorWithFormat
+ ("error with options table; invalid value in has_arg field for option '%c'.\n",
+ (char) val);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid option with value '%c'.\n", (char) val);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ if (!result.Succeeded())
+ break;
+ }
+}
+
+void
+Args::ParseArgsForCompletion
+(
+ Options &options,
+ OptionElementVector &option_element_vector
+)
+{
+ StreamString sstr;
+ int i;
+ 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 (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;
+ }
+ }
+ }
+
+ optreset = 1;
+ optind = 1;
+ opterr = 0;
+
+ int val;
+ const OptionDefinition *opt_defs = options.GetDefinitions();
+
+ // Fooey... getopt_long permutes the GetArgumentVector for no apparent reason.
+ // So we have to build another Arg and pass that to getopt_long so it doesn't
+ // screw up the one we have.
+
+ std::vector<const char *> dummy_vec(GetArgumentVector(), GetArgumentVector() + GetArgumentCount() + 1);
+
+ while (1)
+ {
+ bool missing_argument = false;
+ int parse_start = optind;
+ int long_options_index = -1;
+ val = ::getopt_long (dummy_vec.size() - 1,(char *const *) dummy_vec.data(), sstr.GetData(), long_options,
+ &long_options_index);
+
+ if (val == -1)
+ break;
+
+ else if (val == '?')
+ {
+ option_element_vector.push_back (OptionArgElement (-1, parse_start, -1));
+ 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, parse_start, 0));
+ break;
+ case required_argument:
+ if (optarg != NULL)
+ {
+ int arg_index;
+ if (missing_argument)
+ arg_index = -1;
+ else
+ arg_index = parse_start + 1;
+
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, arg_index));
+ }
+ else
+ {
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, -1));
+ }
+ break;
+ case optional_argument:
+ if (optarg != NULL)
+ {
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, 0));
+ }
+ else
+ {
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, parse_start + 1));
+ }
+ break;
+ default:
+ // The options table is messed up. Here we'll just continue
+ option_element_vector.push_back (OptionArgElement (-1, parse_start, -1));
+ break;
+ }
+ }
+ else
+ {
+ option_element_vector.push_back (OptionArgElement (-1, parse_start, -1));
+ }
+ }
+}
diff --git a/lldb/source/Core/Baton.cpp b/lldb/source/Core/Baton.cpp
new file mode 100644
index 00000000000..103e2e0ef0c
--- /dev/null
+++ b/lldb/source/Core/Baton.cpp
@@ -0,0 +1,25 @@
+//===-- 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
+{
+ s->Printf("baton: %p", m_data);
+}
diff --git a/lldb/source/Core/Broadcaster.cpp b/lldb/source/Core/Broadcaster.cpp
new file mode 100644
index 00000000000..b311a8b3eed
--- /dev/null
+++ b/lldb/source/Core/Broadcaster.cpp
@@ -0,0 +1,219 @@
+//===-- 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 (const char *name) :
+ m_broadcaster_name (name),
+ m_broadcaster_listeners (),
+ m_broadcaster_listeners_mutex (Mutex::eMutexTypeRecursive)
+{
+ 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());
+
+ // Scope for "listeners_locker"
+ {
+ Mutex::Locker listeners_locker(m_broadcaster_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_broadcaster_listeners.end();
+ for (pos = m_broadcaster_listeners.begin(); pos != end; ++pos)
+ pos->first->BroadcasterWillDestruct (this);
+
+ m_broadcaster_listeners.clear();
+ }
+}
+
+const ConstString &
+Broadcaster::GetBroadcasterName ()
+{
+ return m_broadcaster_name;
+}
+
+void
+Broadcaster::AddInitialEventsToListener (Listener *listener, uint32_t requested_events)
+{
+
+}
+
+uint32_t
+Broadcaster::AddListener (Listener* listener, uint32_t event_mask)
+{
+ Mutex::Locker locker(m_broadcaster_listeners_mutex);
+ collection::iterator pos, end = m_broadcaster_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_broadcaster_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_broadcaster_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_broadcaster_listeners_mutex);
+ if (m_broadcaster_listeners.empty())
+ return false;
+
+ collection::iterator pos, end = m_broadcaster_listeners.end();
+ for (pos = m_broadcaster_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_broadcaster_listeners_mutex);
+ collection::iterator pos, end = m_broadcaster_listeners.end();
+ // See if we already have this listener, and if so, update its mask
+ for (pos = m_broadcaster_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_broadcaster_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();
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS);
+ if (log)
+ {
+ StreamString event_description;
+ event_sp->Dump (&event_description);
+ log->Printf ("%p Broadcaster(\"%s\")::BroadcastEvent (event_sp = {%s}, unique =%i)",
+ this,
+ m_broadcaster_name.AsCString(""),
+ event_description.GetData(),
+ unique);
+ }
+
+ Mutex::Locker event_types_locker(m_broadcaster_listeners_mutex);
+ collection::iterator pos, end = m_broadcaster_listeners.end();
+
+
+ // Iterate through all listener/mask pairs
+ for (pos = m_broadcaster_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);
+}
+
diff --git a/lldb/source/Core/Communication.cpp b/lldb/source/Core/Communication.cpp
new file mode 100644
index 00000000000..3ec3e0f41d9
--- /dev/null
+++ b/lldb/source/Core/Communication.cpp
@@ -0,0 +1,363 @@
+//===-- 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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+Communication::Communication(const char *name) :
+ Broadcaster (name),
+ m_connection_ap (),
+ m_read_thread (NULL),
+ m_read_thread_enabled (false),
+ m_bytes(),
+ m_bytes_mutex (Mutex::eMutexTypeRecursive),
+ m_callback (NULL),
+ m_callback_baton (NULL)
+
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::Communication (name = %s)",
+ this, name);
+}
+
+//----------------------------------------------------------------------
+// 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()
+{
+ StopReadThread (NULL);
+ Disconnect (NULL);
+}
+
+ConnectionStatus
+Communication::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
+
+ if (m_connection_ap.get())
+ return m_connection_ap->BytesAvailable (timeout_usec, error_ptr);
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid connection.");
+ return eConnectionStatusNoConnection;
+}
+
+ConnectionStatus
+Communication::Connect (const char *url, Error *error_ptr)
+{
+ Clear();
+
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::Connect (url = %s)", this, url);
+
+ if (m_connection_ap.get())
+ return m_connection_ap->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);
+
+ if (m_connection_ap.get())
+ {
+ ConnectionStatus status = m_connection_ap->Disconnect (error_ptr);
+ m_connection_ap.reset();
+ return status;
+ }
+ return eConnectionStatusNoConnection;
+}
+
+bool
+Communication::IsConnected () const
+{
+ if (m_connection_ap.get())
+ return m_connection_ap->IsConnected ();
+ return false;
+}
+
+bool
+Communication::HasConnection () const
+{
+ return m_connection_ap.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::Write (dst = %p, dst_len = %zu, timeout_usec = %u) connection = %p",
+ this, dst, dst_len, timeout_usec, m_connection_ap.get());
+
+ if (m_read_thread != NULL)
+ {
+ // 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_ap.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.
+ if (m_connection_ap.get())
+ {
+ status = m_connection_ap->BytesAvailable (timeout_usec, error_ptr);
+ if (status == eConnectionStatusSuccess)
+ return m_connection_ap->Read (dst, dst_len, 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_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::Write (src = %p, src_len = %zu) connection = %p",
+ this, src, src_len, m_connection_ap.get());
+
+ if (m_connection_ap.get())
+ return m_connection_ap->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 (m_read_thread != LLDB_INVALID_HOST_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);
+ return m_read_thread != LLDB_INVALID_HOST_THREAD;
+}
+
+bool
+Communication::StopReadThread (Error *error_ptr)
+{
+ if (m_read_thread == NULL)
+ 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);
+
+ return Host::ThreadJoin (m_read_thread, NULL, error_ptr);
+}
+
+
+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.data(), 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)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::AppendBytesToCache (src = %p, src_len = %zu, broadcast = %i)",
+ this, bytes, len, broadcast);
+ if (bytes == NULL || len == 0)
+ 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
+ {
+ 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, ConnectionStatus &status, Error *error_ptr)
+{
+ if (m_connection_ap.get())
+ return m_connection_ap->Read (dst, dst_len, status, error_ptr);
+ return 0;
+}
+
+
+bool
+Communication::ReadThreadIsRunning ()
+{
+ return m_read_thread != NULL;
+}
+
+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)
+ {
+ status = comm->BytesAvailable (UINT32_MAX, &error);
+
+ if (status == eConnectionStatusSuccess)
+ {
+ size_t bytes_read = comm->ReadFromConnection (buf, sizeof(buf), status, &error);
+ if (bytes_read > 0)
+ comm->AppendBytesToCache (buf, bytes_read, true);
+ }
+
+ switch (status)
+ {
+ case eConnectionStatusSuccess:
+ break;
+
+ case eConnectionStatusNoConnection: // No connection
+ case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
+ done = true;
+ // Fall through...
+ default:
+ case eConnectionStatusError: // Check GetError() for details
+ case eConnectionStatusTimedOut: // Request timed out
+ error.LogIfError(log, "%p Communication::BytesAvailable () => status = %i", p, status);
+ break;
+ }
+ }
+ if (log)
+ log->Printf ("%p Communication::ReadThread () thread exiting...", p);
+
+ // Let clients know that this thread is exiting
+ comm->m_read_thread = LLDB_INVALID_HOST_THREAD;
+ 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)
+{
+ StopReadThread(NULL);
+ Disconnect (NULL);
+ m_connection_ap.reset(connection);
+}
diff --git a/lldb/source/Core/Connection.cpp b/lldb/source/Core/Connection.cpp
new file mode 100644
index 00000000000..3c9bb8b1b7e
--- /dev/null
+++ b/lldb/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/lldb/source/Core/ConnectionFileDescriptor.cpp b/lldb/source/Core/ConnectionFileDescriptor.cpp
new file mode 100644
index 00000000000..b22f5ffa36d
--- /dev/null
+++ b/lldb/source/Core/ConnectionFileDescriptor.cpp
@@ -0,0 +1,563 @@
+//===-- ConnectionFileDescriptor.cpp ----------------------------*- 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/ConnectionFileDescriptor.h"
+
+// C Includes
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/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;
+
+ConnectionFileDescriptor::ConnectionFileDescriptor () :
+ Connection(),
+ m_fd (-1),
+ m_should_close_fd (false)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT,
+ "%p ConnectionFileDescriptor::ConnectionFileDescriptor ()",
+ this);
+}
+
+ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) :
+ Connection(),
+ m_fd (fd),
+ m_should_close_fd (owns_fd)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT,
+ "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)",
+ this, fd, owns_fd);
+}
+
+
+ConnectionFileDescriptor::~ConnectionFileDescriptor ()
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT,
+ "%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",
+ this);
+ Disconnect (NULL);
+}
+
+bool
+ConnectionFileDescriptor::IsConnected () const
+{
+ return m_fd >= 0;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
+ "%p ConnectionFileDescriptor::Connect (url = '%s')",
+ this, s);
+
+ 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, "connect://"))
+ {
+ return SocketConnect (s + strlen("connect://"), error_ptr);
+ }
+ else if (strstr(s, "file://"))
+ {
+ // file:///PATH
+ const char *path = s + strlen("file://");
+ m_fd = ::open (path, O_RDWR);
+ if (m_fd == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ int flags = ::fcntl (m_fd, F_GETFL, 0);
+ if (flags >= 0)
+ {
+ if ((flags & O_NONBLOCK) == 0)
+ {
+ flags |= O_NONBLOCK;
+ ::fcntl (m_fd, F_SETFL, flags);
+ }
+ }
+ m_should_close_fd = true;
+ return eConnectionStatusSuccess;
+ }
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Unsupported connection URL: '%s'.\n", s);
+ return eConnectionStatusError;
+ }
+ if (error_ptr)
+ error_ptr->SetErrorString("NULL connection URL.");
+ return eConnectionStatusError;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::Disconnect (Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
+ "%p ConnectionFileDescriptor::Disconnect ()",
+ this);
+ if (m_should_close_fd == false)
+ {
+ m_fd = -1;
+ return eConnectionStatusSuccess;
+ }
+ return Close (m_fd, error_ptr);
+}
+
+size_t
+ConnectionFileDescriptor::Read (void *dst, size_t dst_len, 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 = %zu)...",
+ this, m_fd, dst, dst_len);
+
+ Error error;
+ ssize_t bytes_read = ::read (m_fd, dst, dst_len);
+ if (bytes_read == 0)
+ {
+ error.SetErrorStringWithFormat("End-of-file.\n");
+ status = eConnectionStatusLostConnection;
+ }
+ else if (bytes_read < 0)
+ {
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ error.Clear();
+ }
+
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu) => %zi, error = %s",
+ this,
+ m_fd,
+ dst,
+ dst_len,
+ 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.
+ status = eConnectionStatusSuccess;
+ return 0;
+
+ case EBADF: // fildes is not a valid file or socket descriptor open for reading.
+ 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 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;
+ }
+
+// if (log)
+// error->Log(log, "::read ( %i, %p, %zu ) => %i", m_fd, dst, dst_len, bytesread);
+ Close (m_fd, NULL);
+ 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 = %zu)", this, src, src_len);
+
+ if (!IsConnected ())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Not connected.");
+ status = eConnectionStatusNoConnection;
+ return 0;
+ }
+
+
+ Error error;
+
+ ssize_t bytes_sent = 0;
+
+ if (m_is_socket)
+ bytes_sent = ::send (m_fd, src, src_len, 0);
+ else
+ bytes_sent = ::write (m_fd, src, src_len);
+
+ if (bytes_sent < 0)
+ error.SetErrorToErrno ();
+ else
+ error.Clear ();
+
+ if (log)
+ {
+ if (m_is_socket)
+ log->Printf ("%p ConnectionFileDescriptor::Write() ::send (socket = %i, src = %p, src_len = %zu, flags = 0) => %zi (error = %s)",
+ this, m_fd, src, src_len, bytes_sent, error.AsCString());
+ else
+ log->Printf ("%p ConnectionFileDescriptor::Write() ::write (fd = %i, src = %p, src_len = %zu) => %zi (error = %s)",
+ this, m_fd, src, src_len, bytes_sent, error.AsCString());
+ }
+
+ 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....
+ }
+
+ Close (m_fd, NULL);
+ return 0;
+ }
+
+ status = eConnectionStatusSuccess;
+ return bytes_sent;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ 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;
+ }
+
+ while (IsConnected())
+ {
+ fd_set read_fds;
+ FD_ZERO (&read_fds);
+ FD_SET (m_fd, &read_fds);
+ int nfds = m_fd + 1;
+
+ Error error;
+
+
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::Write() ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p)...",
+ this, nfds, m_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)
+ log->Printf("%p ConnectionFileDescriptor::Write() ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p) => %d, error = %s",
+ this, nfds, m_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.
+ 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)
+ {
+ return eConnectionStatusSuccess;
+ }
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorString("Not connected.");
+ return eConnectionStatusLostConnection;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::Close (int& fd, Error *error_ptr)
+{
+ if (error_ptr)
+ error_ptr->Clear();
+ bool success = true;
+ if (fd >= 0)
+ {
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
+ "%p ConnectionFileDescriptor::Close (fd = %i)",
+ this,
+ fd);
+
+ success = ::close (fd) == 0;
+ 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();
+ }
+ fd = -1;
+ }
+ m_is_socket = false;
+ if (success)
+ return eConnectionStatusSuccess;
+ else
+ return eConnectionStatusError;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
+ "%p ConnectionFileDescriptor::SocketListen (port = %i)",
+ this, listen_port_num);
+
+ Close (m_fd, false);
+ m_is_socket = true;
+ 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);
+
+ struct sockaddr_in sa;
+ ::memset (&sa, 0, sizeof sa);
+ sa.sin_len = sizeof sa;
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons (listen_port_num);
+ sa.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ int err = ::bind (listen_port, (struct sockaddr *) &sa, sizeof(sa));
+ 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 = ::accept (listen_port, NULL, 0);
+ if (m_fd == -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, IPPROTO_TCP, TCP_NODELAY, 1);
+ if (error_ptr)
+ error_ptr->Clear();
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::SocketConnect (const char *host_and_port, Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
+ "%p ConnectionFileDescriptor::SocketConnect (host/port = %s)",
+ this, host_and_port);
+ Close (m_fd, false);
+ m_is_socket = true;
+
+ RegularExpression regex ("([^:]+):([0-9]+)");
+ if (regex.Execute (host_and_port, 2) == false)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Invalid host:port specification: '%s'.\n", host_and_port);
+ return eConnectionStatusError;
+ }
+ std::string host_str;
+ std::string port_str;
+ if (regex.GetMatchAtIndex (host_and_port, 1, host_str) == false ||
+ regex.GetMatchAtIndex (host_and_port, 2, port_str) == false)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Invalid host:port specification '%s'.\n", host_and_port);
+ return eConnectionStatusError;
+ }
+
+ int32_t port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN);
+ if (port == INT32_MIN)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Invalid port '%s'.\n", port_str.c_str());
+ return eConnectionStatusError;
+ }
+ // Create the socket
+ m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (m_fd == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ m_should_close_fd = true;
+
+ // Enable local address reuse
+ SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ struct sockaddr_in sa;
+ ::bzero (&sa, sizeof (sa));
+ sa.sin_len = 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'.\n", host_str.c_str());
+ }
+ Close (m_fd, false);
+ return eConnectionStatusError;
+ }
+ }
+
+ if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa)))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Close (m_fd, false);
+ return eConnectionStatusError;
+ }
+
+ // Keep our TCP packets coming without any delays.
+ SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
+ if (error_ptr)
+ error_ptr->Clear();
+ return eConnectionStatusSuccess;
+}
+
+int
+ConnectionFileDescriptor::SetSocketOption(int fd, int level, int option_name, int option_value)
+{
+ return ::setsockopt(fd, level, option_name, &option_value, sizeof(option_value));
+}
+
+
diff --git a/lldb/source/Core/ConstString.cpp b/lldb/source/Core/ConstString.cpp
new file mode 100644
index 00000000000..c2d09c76461
--- /dev/null
+++ b/lldb/source/Core/ConstString.cpp
@@ -0,0 +1,480 @@
+//===-- 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;
+
+
+//----------------------------------------------------------------------
+// The global string pool is implemented as a hash_map that maps
+// std::string objects to a uint32_t reference count.
+//
+// In debug builds the value that is stored in the ConstString objects is
+// a C string that is owned by one of the std::string objects in the
+// hash map. This was done for visibility purposes when debugging as
+// gcc was often generating insufficient debug info for the
+// iterator objects.
+//
+// In release builds, the value that is stored in the ConstString objects
+// is the iterator into the ConstString::HashMap. This is much faster when
+// it comes to modifying the reference count, and removing strings from
+// the pool.
+//----------------------------------------------------------------------
+class Pool
+{
+public:
+ //------------------------------------------------------------------
+ // Default constructor
+ //
+ // Initialize the member variables and create the empty string.
+ //------------------------------------------------------------------
+ Pool () :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_string_map ()
+ {
+ }
+
+ //------------------------------------------------------------------
+ // Destructor
+ //------------------------------------------------------------------
+ ~Pool ()
+ {
+ }
+
+
+ static llvm::StringMapEntry<uint32_t> &
+ GetStringMapEntryFromKeyData (const char *keyData)
+ {
+ char *ptr = const_cast<char*>(keyData) - sizeof (llvm::StringMapEntry<uint32_t>);
+ return *reinterpret_cast<llvm::StringMapEntry<uint32_t>*>(ptr);
+ }
+
+ size_t
+ GetConstCStringLength (const char *ccstr)
+ {
+ if (ccstr)
+ {
+ llvm::StringMapEntry<uint32_t>&entry = GetStringMapEntryFromKeyData (ccstr);
+ return entry.getKey().size();
+ }
+ return 0;
+ }
+
+ const char *
+ GetConstCString (const char *cstr)
+ {
+ if (cstr)
+ {
+ Mutex::Locker locker (m_mutex);
+ llvm::StringRef string_ref (cstr);
+ llvm::StringMapEntry<uint32_t>& entry = m_string_map.GetOrCreateValue (string_ref);
+ const char *ccstr = entry.getKeyData();
+ llvm::StringMapEntry<uint32_t>&reconstituted_entry = GetStringMapEntryFromKeyData (ccstr);
+ assert (&entry == &reconstituted_entry);
+ return ccstr;
+ }
+ return NULL;
+ }
+
+ const char *
+ GetConstCStringWithLength (const char *cstr, int cstr_len)
+ {
+ if (cstr)
+ {
+ Mutex::Locker locker (m_mutex);
+ llvm::StringRef string_ref (cstr, cstr_len);
+ llvm::StringMapEntry<uint32_t>& entry = m_string_map.GetOrCreateValue (string_ref);
+ const char *ccstr = entry.getKeyData();
+ llvm::StringMapEntry<uint32_t>&reconstituted_entry = GetStringMapEntryFromKeyData (ccstr);
+ assert (&entry == &reconstituted_entry);
+ return ccstr;
+ }
+ return NULL;
+ }
+
+ const char *
+ GetConstTrimmedCStringWithLength (const char *cstr, int cstr_len)
+ {
+ if (cstr)
+ {
+ Mutex::Locker locker (m_mutex);
+ int actual_cstr_len = strlen (cstr);
+ llvm::StringRef string_ref (cstr, std::min<int>(actual_cstr_len, cstr_len));
+ llvm::StringMapEntry<uint32_t>& entry = m_string_map.GetOrCreateValue (string_ref);
+ const char *ccstr = entry.getKeyData();
+ llvm::StringMapEntry<uint32_t>&reconstituted_entry = GetStringMapEntryFromKeyData (ccstr);
+ assert (&entry == &reconstituted_entry);
+ return ccstr;
+ }
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ // Return the size in bytes that this object and any items in its
+ // collection of uniqued strings + reference 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(llvm::StringMapEntry<uint32_t>) + pos->getKey().size();
+ }
+ return mem_size;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Typedefs
+ //------------------------------------------------------------------
+ typedef llvm::StringMap<uint32_t, llvm::BumpPtrAllocator> StringPool;
+ 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.
+//----------------------------------------------------------------------
+static Pool &
+StringPool()
+{
+ static Pool string_pool;
+ return string_pool;
+}
+
+//----------------------------------------------------------------------
+// Default constructor
+//
+// Initializes the string to an empty string.
+//----------------------------------------------------------------------
+ConstString::ConstString () :
+ m_string (NULL)
+{
+}
+
+//----------------------------------------------------------------------
+// Copy constructor
+//
+// Copies the string value in "rhs" and retains an extra reference
+// to the string value in the string pool.
+//----------------------------------------------------------------------
+ConstString::ConstString (const ConstString& rhs) :
+ m_string (rhs.m_string)
+{
+}
+
+//----------------------------------------------------------------------
+// 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 does
+// exist, it retains an extra reference to the string in the string
+// pool. If it doesn't exist, it is added to the string pool with
+// a reference count of 1.
+//----------------------------------------------------------------------
+ConstString::ConstString (const char *cstr) :
+ m_string (StringPool().GetConstCString (cstr))
+{
+}
+
+//----------------------------------------------------------------------
+// Construct with C String value with max length
+//
+// Constructs this object with a C string with a length. If
+// the length of the string is greather than "cstr_len", 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.
+//
+// If the C string already exists in the global string pool, it
+// retains an extra reference to the string in the string
+// pool. If it doesn't exist, it is added to the string pool with
+// a reference count of 1.
+//----------------------------------------------------------------------
+ConstString::ConstString (const char *cstr, size_t cstr_len) :
+ m_string (StringPool().GetConstCStringWithLength (cstr, cstr_len))
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//
+// Decrements the reference count on the contained string, and if
+// the resulting reference count is zero, then the string is removed
+// from the string pool. If the reference count is still greater
+// than zero, the string will remain in the string pool
+//----------------------------------------------------------------------
+ConstString::~ConstString ()
+{
+}
+
+//----------------------------------------------------------------------
+// Convert to pointer operator. This allows code to check any
+// ConstString objects to see if they contain anything (not empty)
+// valid using code such as:
+//
+// ConstString str(...);
+// if (str)
+// { ...
+//----------------------------------------------------------------------
+ConstString::operator void*() const
+{
+ return IsEmpty() ? NULL : const_cast<ConstString*>(this);
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//
+// Assigns the string in this object with the value from "rhs"
+// and increments the reference count of that string.
+//
+// The previously contained string will be get its reference count
+// decremented and removed from the string pool if its reference
+// count reaches zero.
+//----------------------------------------------------------------------
+const ConstString&
+ConstString::operator=(const ConstString& rhs)
+{
+ m_string = rhs.m_string;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Equal to operator
+//
+// Returns true if this string is equal to that in "rhs". This is
+// very fast as it results in a pointer comparison since all strings
+// are in a uniqued and reference counted string pool.
+//------------------------------------------------------------------
+bool
+ConstString::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;
+}
+
+bool
+ConstString::operator != (const ConstString& rhs) const
+{
+ return m_string != rhs.m_string;
+}
+
+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 the string value "str" to the stream "s"
+//----------------------------------------------------------------------
+Stream&
+lldb_private::operator << (Stream& s, const ConstString& str)
+{
+ const char *cstr = str.GetCString();
+ if (cstr)
+ s << cstr;
+
+ return s;
+}
+
+//----------------------------------------------------------------------
+// Get the value of the contained string as a NULL terminated C
+// string value. Return "fail_value" if the string is empty.
+//----------------------------------------------------------------------
+const char *
+ConstString::AsCString(const char *fail_value) const
+{
+ if (m_string == NULL)
+ return fail_value;
+ return m_string;
+}
+
+const char *
+ConstString::GetCString () const
+{
+ return m_string;
+}
+
+size_t
+ConstString::GetLength () const
+{
+ return StringPool().GetConstCStringLength (m_string);
+}
+
+
+//----------------------------------------------------------------------
+// Clear any contained string and reset the value to the an empty
+// string value.
+//
+// The previously contained string will be get its reference count
+// decremented and removed from the string pool if its reference
+// count reaches zero.
+//----------------------------------------------------------------------
+void
+ConstString::Clear ()
+{
+ m_string = NULL;
+}
+
+//----------------------------------------------------------------------
+// Compare two string objects.
+//
+// Returns:
+// -1 if a < b
+// 0 if a == b
+// 1 if a > b
+//----------------------------------------------------------------------
+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
+}
+
+//----------------------------------------------------------------------
+// Dump the string value to the stream "s". If the contained string
+// is empty, print "fail_value" to the stream instead. If
+// "fail_value" is NULL, then nothing will be dumped to the
+// stream.
+//----------------------------------------------------------------------
+void
+ConstString::Dump(Stream *s, const char *fail_value) const
+{
+ const char *cstr = AsCString (fail_value);
+ if (cstr)
+ s->PutCString (cstr);
+}
+
+//----------------------------------------------------------------------
+// Dump extra debug information to the stream "s".
+//----------------------------------------------------------------------
+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 = %zu", (int)sizeof(void*) * 2, this, parens, cstr, parens, cstr_len);
+}
+
+//----------------------------------------------------------------------
+// Returns true if the contained string is empty.
+//----------------------------------------------------------------------
+bool
+ConstString::IsEmpty() const
+{
+ return m_string == NULL || m_string[0] == '\0';
+}
+
+//----------------------------------------------------------------------
+// Set the string value in the object by uniquing the "cstr" string
+// value in our global string pool.
+//
+// If the C string already exists in the global string pool, it
+// retains an extra reference to the string in the string
+// pool. If it doesn't exist, it is added to the string pool with
+// a reference count of 1.
+//----------------------------------------------------------------------
+void
+ConstString::SetCString (const char *cstr)
+{
+ m_string = StringPool().GetConstCString (cstr);
+}
+
+//----------------------------------------------------------------------
+// Set the string value in the object by uniquing "cstr_len" bytes
+// starting at the "cstr" string value in our global string pool.
+// If trim is true, then "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 trim is false, then this allows strings
+// with NULL characters ('\0') to be added to the string pool.
+//
+// If the C string already exists in the global string pool, it
+// retains an extra reference to the string in the string
+// pool. If it doesn't exist, it is added to the string pool with
+// a reference count of 1.
+//----------------------------------------------------------------------
+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);
+}
+
+//----------------------------------------------------------------------
+// Return the size in bytes that this object takes in memory. The
+// resulting size will not include any of the C string values from
+// the global string pool (see StaticMemorySize ()).
+//----------------------------------------------------------------------
+size_t
+ConstString::MemorySize() const
+{
+ return sizeof(ConstString);
+}
+
+//----------------------------------------------------------------------
+// Reports the the size in bytes of all shared C string values,
+// containers and reference count values as a byte size for the
+// entire string pool.
+//----------------------------------------------------------------------
+size_t
+ConstString::StaticMemorySize()
+{
+ // Get the size of the static string pool
+ return StringPool().MemorySize();
+}
diff --git a/lldb/source/Core/DataBufferHeap.cpp b/lldb/source/Core/DataBufferHeap.cpp
new file mode 100644
index 00000000000..a93427ff858
--- /dev/null
+++ b/lldb/source/Core/DataBufferHeap.cpp
@@ -0,0 +1,105 @@
+//===-- 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 (size_t n, uint8_t ch) :
+ m_data(n, ch)
+{
+}
+
+//----------------------------------------------------------------------
+// Initialize this class with a copy of the "n" bytes from the "bytes"
+// buffer.
+//----------------------------------------------------------------------
+DataBufferHeap::DataBufferHeap (const void *src, size_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.
+//----------------------------------------------------------------------
+size_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.
+//----------------------------------------------------------------------
+size_t
+DataBufferHeap::SetByteSize (size_t new_size)
+{
+ m_data.resize(new_size);
+ return m_data.size();
+}
+
+void
+DataBufferHeap::CopyData (const void *src, size_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();
+}
+
+
+
diff --git a/lldb/source/Core/DataBufferMemoryMap.cpp b/lldb/source/Core/DataBufferMemoryMap.cpp
new file mode 100644
index 00000000000..c8ad5492f51
--- /dev/null
+++ b/lldb/source/Core/DataBufferMemoryMap.cpp
@@ -0,0 +1,214 @@
+//===-- 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 <sys/stat.h>
+#include <sys/mman.h>
+
+#include "lldb/Core/DataBufferMemoryMap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Host/Host.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default Constructor
+//----------------------------------------------------------------------
+DataBufferMemoryMap::DataBufferMemoryMap() :
+ m_mmap_addr(NULL),
+ m_mmap_size(0),
+ m_data(NULL),
+ m_size(0),
+ m_error()
+{
+}
+
+//----------------------------------------------------------------------
+// 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.
+//----------------------------------------------------------------------
+size_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)
+ {
+ ::munmap((void *)m_mmap_addr, m_mmap_size);
+ m_mmap_addr = NULL;
+ m_mmap_size = 0;
+ m_data = NULL;
+ m_size = 0;
+ }
+ m_error.Clear();
+}
+
+
+const Error &
+DataBufferMemoryMap::GetError() const
+{
+ return m_error;
+}
+
+//----------------------------------------------------------------------
+// Memory map "length" bytes from "file" starting "offset"
+// bytes into the file. If "length" is set to SIZE_T_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* file, off_t offset, size_t length)
+{
+ if (file != NULL)
+ {
+ char path[PATH_MAX];
+ if (file->GetPath(path, sizeof(path)))
+ {
+ int fd = ::open(path, O_RDONLY, 0);
+ if (fd >= 0)
+ {
+ MemoryMapFromFileDescriptor (fd, offset, length);
+ ::close(fd);
+ return GetByteSize();
+ }
+ else
+ {
+ m_error.SetErrorToErrno();
+ return 0;
+ }
+ }
+ }
+ // 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_T_MAX, then map as many bytes
+// as possible.
+//
+// RETURNS
+// Number of bytes mapped starting from the requested offset.
+//----------------------------------------------------------------------
+size_t
+DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, off_t offset, size_t length)
+{
+ Clear();
+ if (fd >= 0)
+ {
+ struct stat stat;
+ if (::fstat(fd, &stat) == 0)
+ {
+ if ((stat.st_mode & S_IFREG) && (stat.st_size > offset))
+ {
+ if (length == SIZE_T_MAX)
+ length = stat.st_size - offset;
+
+ // Cap the length if too much data was requested
+ if (length > stat.st_size - offset)
+ length = stat.st_size - offset;
+
+ if (length > 0)
+ {
+ m_mmap_addr = (uint8_t *)::mmap(NULL, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, offset);
+
+ if (m_mmap_addr == (void*)-1)
+ {
+ m_error.SetErrorToErrno ();
+ if (m_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_READ, MAP_FILE | MAP_SHARED, 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
+ m_error.Clear ();
+
+ // 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;
+ }
+ }
+ }
+ }
+ 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;
+ }
+ }
+ }
+ }
+
+ ::close (fd);
+ }
+ return GetByteSize ();
+}
diff --git a/lldb/source/Core/DataExtractor.cpp b/lldb/source/Core/DataExtractor.cpp
new file mode 100644
index 00000000000..236ec187f5f
--- /dev/null
+++ b/lldb/source/Core/DataExtractor.cpp
@@ -0,0 +1,1517 @@
+//===-- 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 <libkern/OSByteOrder.h>
+#include <stddef.h>
+
+#include <bitset>
+#include <string>
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/DataBuffer.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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define NON_PRINTABLE_CHAR '.'
+//----------------------------------------------------------------------
+// Default constructor.
+//----------------------------------------------------------------------
+DataExtractor::DataExtractor () :
+ m_start (NULL),
+ m_end (NULL),
+ m_byte_order(eByteOrderHost),
+ 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, 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 DataExtractor objects exist that have a reference to
+// this data.
+//----------------------------------------------------------------------
+DataExtractor::DataExtractor (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);
+}
+
+//----------------------------------------------------------------------
+// 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, uint32_t offset, uint32_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))
+ {
+ uint32_t bytes_available = data.GetByteSize() - offset;
+ if (length > bytes_available)
+ length = bytes_available;
+ SetData(data, offset, length);
+ }
+}
+
+//----------------------------------------------------------------------
+// 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 = eByteOrderHost;
+ m_addr_size = 4;
+ m_data_sp.reset();
+}
+
+//------------------------------------------------------------------
+// Returns the total number of bytes that this object refers to
+//------------------------------------------------------------------
+size_t
+DataExtractor::GetByteSize () const
+{
+ return m_end - m_start;
+}
+
+//------------------------------------------------------------------
+// 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;
+}
+
+//------------------------------------------------------------------
+// Returns true if OFFSET is a valid offset into the data in this
+// object.
+//------------------------------------------------------------------
+bool
+DataExtractor::ValidOffset (uint32_t offset) const
+{
+ return offset < GetByteSize();
+}
+
+//------------------------------------------------------------------
+// Returns true if there are LENGTH bytes availabe starting OFFSET
+// into the data that is in this object.
+//------------------------------------------------------------------
+bool
+DataExtractor::ValidOffsetForDataOfSize (uint32_t offset, uint32_t length) const
+{
+ size_t size = GetByteSize();
+ if (offset >= size)
+ return false; // offset isn't valid
+
+ if (length == 0)
+ return true; // No bytes requested at this offset, return true
+
+ // If we flip the bits in offset we can figure out how
+ // many bytes we have left before "offset + length"
+ // could overflow when doing unsigned arithmetic.
+ if (length > ~offset)
+ return false; // unsigned overflow
+
+ // Make sure "offset + length" is a valid offset as well.
+ // length must be greater than zero for this to be a
+ // valid expression, and we have already checked for this.
+ return ((offset + length) <= size);
+}
+
+//------------------------------------------------------------------
+// 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 *
+DataExtractor::GetDataStart () const
+{
+ return m_start;
+}
+//------------------------------------------------------------------
+// Returns a pointer to the byte past the last byte contained in
+// this object's data, or NULL of there is no data in this object.
+//------------------------------------------------------------------
+const uint8_t *
+DataExtractor::GetDataEnd () const
+{
+ return m_end;
+}
+
+//------------------------------------------------------------------
+// Returns true if this object will endian swap values as it
+// extracts data.
+//------------------------------------------------------------------
+ByteOrder
+DataExtractor::GetByteOrder () const
+{
+ return m_byte_order;
+}
+//------------------------------------------------------------------
+// Set wether this object will endian swap values as it extracts
+// data.
+//------------------------------------------------------------------
+void
+DataExtractor::SetByteOrder (ByteOrder endian)
+{
+ m_byte_order = endian;
+}
+
+
+//------------------------------------------------------------------
+// Return the size in bytes of any address values this object will
+// extract
+//------------------------------------------------------------------
+uint8_t
+DataExtractor::GetAddressByteSize () const
+{
+ return m_addr_size;
+}
+
+//------------------------------------------------------------------
+// Set the size in bytes that will be used when extracting any
+// address values from data contained in this object.
+//------------------------------------------------------------------
+void
+DataExtractor::SetAddressByteSize (uint8_t addr_size)
+{
+ m_addr_size = addr_size;
+}
+
+//----------------------------------------------------------------------
+// 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
+DataExtractor::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 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".
+//----------------------------------------------------------------------
+uint32_t
+DataExtractor::SetData (const DataExtractor& data, uint32_t data_offset, uint32_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.
+//----------------------------------------------------------------------
+uint32_t
+DataExtractor::SetData (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.
+//----------------------------------------------------------------------
+uint8_t
+DataExtractor::GetU8 (uint32_t *offset_ptr) const
+{
+ uint8_t val = 0;
+ if ( m_start < m_end )
+ {
+ val = m_start[*offset_ptr];
+ *offset_ptr += sizeof(val);
+ }
+ return val;
+}
+
+//----------------------------------------------------------------------
+// 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 (uint32_t *offset_ptr, void *dst, uint32_t count) const
+{
+ register uint32_t offset = *offset_ptr;
+
+ if ((count > 0) && ValidOffsetForDataOfSize(offset, count) )
+ {
+ // Copy the data into the buffer
+ memcpy (dst, m_start + offset, count);
+ // Advance the offset
+ *offset_ptr += 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 (uint32_t *offset_ptr) const
+{
+ uint16_t val = 0;
+ register uint32_t offset = *offset_ptr;
+ if ( ValidOffsetForDataOfSize(offset, sizeof(val)) )
+ {
+ if (m_byte_order != eByteOrderHost)
+ val = OSReadSwapInt16(m_start, offset);
+ else
+ val = _OSReadInt16 (m_start, offset);
+
+ // Advance the offset
+ *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 (uint32_t *offset_ptr, void *void_dst, uint32_t count) const
+{
+ uint16_t *dst = (uint16_t *)void_dst;
+ const size_t value_size = sizeof(*dst);
+ register uint32_t offset = *offset_ptr;
+
+ if ((count > 0) && ValidOffsetForDataOfSize(offset, value_size * count) )
+ {
+ uint16_t *value_ptr;
+ uint16_t *end = dst + count;
+ if (m_byte_order != eByteOrderHost)
+ {
+ for (value_ptr = dst; value_ptr < end; ++value_ptr, offset += value_size)
+ *value_ptr = OSReadSwapInt16 (m_start, offset);
+ }
+ else
+ {
+ for (value_ptr = dst; value_ptr < end; ++value_ptr, offset += value_size)
+ *value_ptr = _OSReadInt16 (m_start, offset);
+ }
+
+ // Advance the offset
+ *offset_ptr = offset;
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return 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 (uint32_t *offset_ptr) const
+{
+ uint32_t val = 0;
+ register uint32_t offset = *offset_ptr;
+
+ if ( ValidOffsetForDataOfSize(offset, sizeof(val)) )
+ {
+ if (m_byte_order != eByteOrderHost)
+ val = OSReadSwapInt32 (m_start, offset);
+ else
+ val = _OSReadInt32 (m_start, offset);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ 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 (uint32_t *offset_ptr, void *void_dst, uint32_t count) const
+{
+ uint32_t *dst = (uint32_t *)void_dst;
+ const size_t value_size = sizeof(*dst);
+ register uint32_t offset = *offset_ptr;
+
+ if ((count > 0) && ValidOffsetForDataOfSize(offset, value_size * count))
+ {
+ uint32_t *value_ptr;
+ uint32_t *end = dst + count;
+ if (m_byte_order != eByteOrderHost)
+ {
+ for (value_ptr = dst; value_ptr < end; ++value_ptr, offset += value_size)
+ *value_ptr = OSReadSwapInt32 (m_start, offset);
+
+ }
+ else
+ {
+ for (value_ptr = dst; value_ptr < end; ++value_ptr, offset += value_size)
+ *value_ptr = _OSReadInt32 (m_start, offset);
+ }
+
+ // Advance the offset
+ *offset_ptr = offset;
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return 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 (uint32_t *offset_ptr) const
+{
+ uint64_t val = 0;
+ register uint32_t offset = *offset_ptr;
+ if ( ValidOffsetForDataOfSize(offset, sizeof(val)) )
+ {
+ if (m_byte_order != eByteOrderHost)
+ val = OSReadSwapInt64 (m_start, offset);
+ else
+ val = _OSReadInt64 (m_start, offset);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ 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 (uint32_t *offset_ptr, void *void_dst, uint32_t count) const
+{
+ uint64_t *dst = (uint64_t *)void_dst;
+ const size_t value_size = sizeof(uint64_t);
+ register uint32_t offset = *offset_ptr;
+
+ if ((count > 0) && ValidOffsetForDataOfSize(offset, value_size * count))
+ {
+ uint64_t *value_ptr;
+ uint64_t *end = dst + count;
+ if (m_byte_order != eByteOrderHost)
+ {
+ for (value_ptr = dst; value_ptr < end; ++value_ptr, offset += value_size)
+ *value_ptr = OSReadSwapInt64 (m_start, offset);
+
+ }
+ else
+ {
+ for (value_ptr = dst; value_ptr < end; ++value_ptr, offset += value_size)
+ *value_ptr = _OSReadInt64 (m_start, offset);
+ }
+
+ // Advance the offset
+ *offset_ptr = offset;
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return 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 (uint32_t *offset_ptr, uint32_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!");
+ 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 (uint32_t *offset_ptr, uint32_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!");
+ break;
+ }
+ return 0;
+}
+
+int64_t
+DataExtractor::GetMaxS64 (uint32_t *offset_ptr, uint32_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!");
+ break;
+ }
+ return 0;
+}
+
+uint64_t
+DataExtractor::GetMaxU64Bitfield (uint32_t *offset_ptr, uint32_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 = ((1 << bitfield_bit_size) - 1);
+ uval64 &= bitfield_mask;
+ }
+ return uval64;
+}
+
+int64_t
+DataExtractor::GetMaxS64Bitfield (uint32_t *offset_ptr, uint32_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 = ((1 << bitfield_bit_size) - 1);
+ sval64 &= bitfield_mask;
+ // sign extend if needed
+ if (sval64 & (1 << (bitfield_bit_size - 1)))
+ sval64 |= ~bitfield_mask;
+ }
+ return sval64;
+}
+
+
+float
+DataExtractor::GetFloat (uint32_t *offset_ptr) const
+{
+ uint32_t val = 0;
+ register uint32_t offset = *offset_ptr;
+
+ if ( ValidOffsetForDataOfSize(offset, sizeof(val)) )
+ {
+ if (m_byte_order != eByteOrderHost)
+ val = OSReadSwapInt32 (m_start, offset);
+ else
+ val = _OSReadInt32 (m_start, offset);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ return *((float *)&val);
+}
+
+double
+DataExtractor::GetDouble (uint32_t *offset_ptr) const
+{
+ uint64_t val = 0;
+ register uint32_t offset = *offset_ptr;
+ if ( ValidOffsetForDataOfSize(offset, sizeof(val)) )
+ {
+ if (m_byte_order != eByteOrderHost)
+ val = OSReadSwapInt64 (m_start, offset);
+ else
+ val = _OSReadInt64 (m_start, offset);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ return *((double *)&val);
+
+}
+
+
+long double
+DataExtractor::GetLongDouble (uint32_t *offset_ptr) const
+{
+ if (sizeof(long double) == sizeof(uint64_t))
+ {
+ uint64_t val = 0;
+ register uint32_t offset = *offset_ptr;
+ if ( ValidOffsetForDataOfSize(offset, sizeof(val)) )
+ {
+ if (m_byte_order != eByteOrderHost)
+ val = OSReadSwapInt64 (m_start, offset);
+ else
+ val = _OSReadInt64 (m_start, offset);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ return *((long double *)&val);
+ }
+ return 0.0;
+}
+
+
+//------------------------------------------------------------------
+// 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 (uint32_t *offset_ptr) const
+{
+ return GetMaxU64 (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 (uint32_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 (uint32_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_GNU_EH_PE_omit)
+ return ULONG_LONG_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_GNU_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_GNU_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_GNU_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_GNU_EH_PE_funcrel:
+ signExtendValue = true;
+ break;
+
+ case DW_GNU_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_GNU_EH_PE_MASK_ENCODING)
+ {
+ case DW_GNU_EH_PE_absptr :
+ {
+ addressValue = GetAddress (offset_ptr);
+// if (data_relocs)
+// addressValue = data_relocs->Relocate(*offset_ptr - addr_size, *this, addressValue);
+ }
+ break;
+ case DW_GNU_EH_PE_uleb128 : addressValue = GetULEB128(offset_ptr); break;
+ case DW_GNU_EH_PE_udata2 : addressValue = GetU16(offset_ptr); break;
+ case DW_GNU_EH_PE_udata4 : addressValue = GetU32(offset_ptr); break;
+ case DW_GNU_EH_PE_udata8 : addressValue = GetU64(offset_ptr); break;
+ case DW_GNU_EH_PE_sleb128 : addressValue = GetSLEB128(offset_ptr); break;
+ case DW_GNU_EH_PE_sdata2 : addressValue = (int16_t)GetU16(offset_ptr); break;
+ case DW_GNU_EH_PE_sdata4 : addressValue = (int32_t)GetU32(offset_ptr); break;
+ case DW_GNU_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 (uint32_t offset, uint32_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;
+}
+//----------------------------------------------------------------------
+// Peeks at bytes in the contained data.
+//
+// Returns a valid pointer to bytes if "offset" is a valid offset in
+// and there are "length" bytes available, else NULL is returned.
+//----------------------------------------------------------------------
+const uint8_t*
+DataExtractor::PeekData (uint32_t offset, uint32_t length) const
+{
+ if ( length > 0 && ValidOffsetForDataOfSize(offset, length) )
+ return m_start + offset;
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Returns a pointer to a bytes in this object's data at the offset
+// pointed to by "offset_ptr". If "length" is zero or too large,
+// then the offset pointed to by "offset_ptr" will not be updated
+// and NULL will be returned.
+//
+// Returns a pointer to the data if the offset and length are valid,
+// or NULL otherwise.
+//----------------------------------------------------------------------
+const void*
+DataExtractor::GetData (uint32_t *offset_ptr, uint32_t length) const
+{
+ const uint8_t* bytes = NULL;
+ register uint32_t offset = *offset_ptr;
+ if ( length > 0 && ValidOffsetForDataOfSize(offset, length) )
+ {
+ bytes = m_start + offset;
+ *offset_ptr = offset + length;
+ }
+ return bytes;
+}
+
+//----------------------------------------------------------------------
+// Extracts a AsCString (fixed length, or variable length) from
+// the data at the offset pointed to by "offset_ptr". If
+// "length" is zero, then a variable length NULL terminated C
+// string will be extracted from the data the "offset_ptr" will be
+// updated with the offset of the byte that follows the NULL
+// terminator byte. If "length" is greater than zero, then
+// the function will make sure there are "length" bytes
+// available in the current data and if so, return a valid pointer.
+//
+// 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 (uint32_t *offset_ptr) const
+{
+ const char *s = NULL;
+ if ( m_start < m_end )
+ {
+ s = (char*)m_start + *offset_ptr;
+
+ size_t length = strlen(s) + 1;
+
+ if (!ValidOffsetForDataOfSize(*offset_ptr, length))
+ return NULL;
+
+ // Advance the offset
+ *offset_ptr += length;
+ }
+ return s;
+}
+
+//------------------------------------------------------------------
+// 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 (uint32_t offset) const
+{
+ if (ValidOffset (offset))
+ return (const char*)m_start + offset;
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// 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 (uint32_t *offset_ptr) const
+{
+ uint64_t result = 0;
+ if ( m_start < m_end )
+ {
+ int shift = 0;
+ const uint8_t *src = m_start + *offset_ptr;
+ uint8_t byte;
+ int bytecount = 0;
+
+ while (src < m_end)
+ {
+ bytecount++;
+ byte = *src++;
+ result |= (byte & 0x7f) << shift;
+ shift += 7;
+ if ((byte & 0x80) == 0)
+ break;
+ }
+
+ *offset_ptr += bytecount;
+ }
+ return result;
+}
+
+//----------------------------------------------------------------------
+// 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 (uint32_t *offset_ptr) const
+{
+ int64_t result = 0;
+
+ if ( m_start < m_end )
+ {
+ int shift = 0;
+ int size = sizeof (uint32_t) * 8;
+ const uint8_t *src = m_start + *offset_ptr;
+
+ uint8_t byte;
+ int bytecount = 0;
+
+ while (src < m_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;
+}
+
+//----------------------------------------------------------------------
+// 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 (uint32_t *offset_ptr) const
+{
+ uint32_t bytes_consumed = 0;
+ if ( m_start < m_end )
+ {
+ const uint8_t *start = m_start + *offset_ptr;
+ const uint8_t *src = start;
+
+ while ((src < m_end) && (*src++ & 0x80))
+ ++bytes_consumed;
+
+ *offset_ptr += src - start;
+ }
+ return bytes_consumed;
+}
+
+uint32_t
+DataExtractor::Dump
+(
+ Stream *s,
+ uint32_t start_offset,
+ lldb::Format item_format,
+ uint32_t item_byte_size,
+ uint32_t item_count,
+ uint32_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
+) const
+{
+ if (s == NULL)
+ return start_offset;
+
+ uint32_t offset;
+ uint32_t count;
+ uint32_t line_start_offset;
+
+ if (item_format == eFormatPointer)
+ {
+ if (item_byte_size != 4 && item_byte_size != 8)
+ item_byte_size = s->GetAddressByteSize();
+ }
+
+ for (offset = start_offset, line_start_offset = start_offset, 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", (num_per_line - (offset - line_start_offset)) * 3 + 2, "");
+ Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
+ }
+ s->EOL();
+ }
+ if (base_addr != LLDB_INVALID_ADDRESS)
+ s->Printf ("0x%8.8llx: ", (uint64_t)(base_addr + (offset - start_offset)));
+ line_start_offset = offset;
+ }
+ else
+ if (item_format != eFormatChar &&
+ item_format != eFormatCharPrintable &&
+ count > 0)
+ {
+ s->PutChar(' ');
+ }
+
+ uint32_t i;
+ switch (item_format)
+ {
+ case eFormatBoolean:
+ s->Printf ("%s", GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset) ? "true" : "false");
+ break;
+
+ case eFormatBinary:
+ {
+ uint64_t uval64 = GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset);
+ std::string binary_value(std::bitset<64>(uval64).to_string());
+ 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);
+ }
+ 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:
+ {
+ // If we are only printing one character surround it with single
+ // quotes
+ if (item_count == 1 && item_format == eFormatChar)
+ s->PutChar('\'');
+
+ uint8_t ch = GetU8(&offset);
+ if (isprint(ch))
+ s->Printf ("%c", ch);
+ else if (item_format == eFormatChar)
+ {
+ switch (ch)
+ {
+ case '\e': s->Printf ("\\e", (uint8_t)ch); break;
+ case '\a': s->Printf ("\\a", ch); break;
+ case '\b': s->Printf ("\\b", ch); break;
+ case '\f': s->Printf ("\\f", ch); break;
+ case '\n': s->Printf ("\\n", ch); break;
+ case '\r': s->Printf ("\\r", ch); break;
+ case '\t': s->Printf ("\\t", ch); break;
+ case '\v': s->Printf ("\\v", ch); break;
+ case '\0': s->Printf ("\\0", ch); break;
+ default: s->Printf ("\\x%2.2x", 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 eFormatComplex:
+ if (sizeof(float) * 2 == item_byte_size)
+ {
+ uint32_t a32 = GetU32(&offset);
+ uint32_t b32 = GetU32(&offset);
+
+ s->Printf ("%g + %gi", a32, b32);
+ }
+ else if (sizeof(double) * 2 == item_byte_size)
+ {
+ uint64_t a64 = GetU64(&offset);
+ uint64_t b64 = GetU64(&offset);
+
+ s->Printf ("%lg + %lgi", a64, b64);
+ }
+ else if (sizeof(long double) * 2 == item_byte_size && sizeof(long double) <= sizeof(uint64_t))
+ {
+ uint64_t a64 = GetU64(&offset);
+ uint64_t b64 = GetU64(&offset);
+ s->Printf ("%Lg + %Lgi", a64, b64);
+ }
+ break;
+
+ case eFormatDecimal:
+ if (item_byte_size <= 8);
+ s->Printf ("%lld", GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ break;
+
+ case eFormatUnsigned:
+ if (item_byte_size <= 8);
+ s->Printf ("%llu", GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ break;
+
+ case eFormatOctal:
+ if (item_byte_size <= 8);
+ s->Printf ("0%llo", GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ break;
+
+ case eFormatEnum:
+ // Print enum value as a signed integer when we don't get the enum type
+ s->Printf ("%lld", GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ break;
+
+ case eFormatCString:
+ {
+ const char *cstr = GetCStr(&offset);
+ if (cstr)
+ s->Printf("\"%s\"", cstr);
+ else
+ {
+ s->Printf("NULL", cstr);
+ offset = UINT32_MAX;
+ }
+ }
+ break;
+
+
+ case eFormatPointer:
+ s->Address(GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset), sizeof (addr_t));
+ break;
+
+ case eFormatHex:
+ if (item_byte_size <= 8)
+ {
+ s->Printf("0x%*.*llx", 2 * item_byte_size, 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");
+ int32_t start_idx, end_idx, delta;
+ if (m_byte_order == eByteOrderBig)
+ {
+ start_idx = offset;
+ end_idx = offset + item_byte_size;
+ delta = 1;
+ }
+ else
+ {
+ start_idx = offset + item_byte_size - 1;
+ end_idx = -1;
+ delta = -1;
+ }
+ const uint8_t *bytes = (const uint8_t* )GetData(&offset, item_byte_size);
+ if (bytes)
+ {
+ for (int32_t idx = start_idx; idx != end_idx; idx += delta)
+ s->Printf("%2.2x", bytes[idx]);
+ }
+ }
+ break;
+
+ case eFormatFloat:
+ if (sizeof(float) == item_byte_size)
+ {
+ uint32_t a32 = GetU32(&offset);
+ s->Printf ("%g", (double)(*((float *)&a32)));
+ }
+ else if (sizeof(double) == item_byte_size)
+ {
+ uint64_t a64 = GetU64(&offset);
+ s->Printf ("%lg", (*((double *)&a64)));
+ }
+ else if (sizeof(long double) == item_byte_size && sizeof(long double) <= sizeof(uint64_t))
+ {
+ uint64_t a64 = GetU64(&offset);
+ s->Printf ("%Lg", (*((long double *)&a64)));
+ }
+ break;
+
+ case eFormatUnicode16:
+ s->Printf("0x%4.4x", GetU16 (&offset));
+ break;
+
+ case eFormatUnicode32:
+ s->Printf("0x%8.8x", GetU32 (&offset));
+ break;
+
+ case eFormatVectorOfChar:
+ s->PutChar('{');
+ offset = Dump (s, start_offset, eFormatChar, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt8:
+ s->PutChar('{');
+ offset = Dump (s, start_offset, eFormatDecimal, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt8:
+ s->PutChar('{');
+ offset = Dump (s, start_offset, eFormatHex, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt16:
+ s->PutChar('{');
+ offset = Dump (s, start_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, start_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, start_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, start_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, start_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, start_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 eFormatVectorOfFloat32:
+ s->PutChar('{');
+ offset = Dump (s, start_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, start_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, start_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", (num_per_line - (offset - line_start_offset)) * 3 + 2, "");
+ Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, UINT32_MAX, 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().
+//----------------------------------------------------------------------
+uint32_t
+DataExtractor::PutToLog
+(
+ Log *log,
+ uint32_t start_offset,
+ uint32_t length,
+ uint64_t base_addr,
+ uint32_t num_per_line,
+ DataExtractor::Type type,
+ const char *format
+) const
+{
+ if (log == NULL)
+ return start_offset;
+
+ uint32_t offset;
+ uint32_t end_offset = offset + length;
+ uint32_t count;
+ StreamString sstr;
+ for (offset = start_offset, 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.8llx:", (uint64_t)(base_addr + (offset - start_offset)));
+ }
+
+ switch (type)
+ {
+ default:
+ 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.16llx", GetU64(&offset)); break;
+ case TypePointer: sstr.Printf (format ? format : " 0x%llx", GetAddress(&offset)); break;
+ case TypeULEB128: sstr.Printf (format ? format : " 0x%llx", GetULEB128(&offset)); break;
+ case TypeSLEB128: sstr.Printf (format ? format : " %lld", 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, uint32_t offset) const
+{
+ if (s)
+ {
+ const uint8_t *uuid_data = PeekData(offset, 16);
+ if ( uuid_data )
+ {
+ UUID uuid(uuid_data, 16);
+ uuid.Dump(s);
+ }
+ else
+ {
+ s->Printf("<not enough data for UUID at offset 0x%8.8x>", offset);
+ }
+ }
+}
+
+
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
new file mode 100644
index 00000000000..c106d838fed
--- /dev/null
+++ b/lldb/source/Core/Debugger.cpp
@@ -0,0 +1,434 @@
+//===-- 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-private.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Timer.h"
+
+#include "lldb/Target/TargetList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+int Debugger::g_shared_debugger_refcount = 0;
+bool Debugger::g_in_terminate = false;
+
+Debugger::DebuggerSP &
+Debugger::GetDebuggerSP ()
+{
+ static DebuggerSP g_shared_debugger_sp;
+ return g_shared_debugger_sp;
+}
+
+void
+Debugger::Initialize ()
+{
+ g_shared_debugger_refcount++;
+ if (GetDebuggerSP().get() == NULL)
+ {
+ GetDebuggerSP().reset (new Debugger());
+ lldb_private::Initialize();
+ GetDebuggerSP()->GetCommandInterpreter().Initialize();
+ }
+}
+
+void
+Debugger::Terminate ()
+{
+ g_shared_debugger_refcount--;
+ if (g_shared_debugger_refcount == 0)
+ {
+ // Because Terminate is called also in the destructor, we need to make sure
+ // that none of the calls to GetSharedInstance leads to a call to Initialize,
+ // thus bumping the refcount back to 1 & causing Debugger::~Debugger to try to
+ // re-terminate. So we use g_in_terminate to indicate this condition.
+ // When we can require at least Initialize to be called, we won't have to do
+ // this since then the GetSharedInstance won't have to auto-call Initialize...
+
+ g_in_terminate = true;
+ int num_targets = GetDebuggerSP()->GetTargetList().GetNumTargets();
+ for (int i = 0; i < num_targets; i++)
+ {
+ ProcessSP process_sp(GetDebuggerSP()->GetTargetList().GetTargetAtIndex (i)->GetProcessSP());
+ if (process_sp)
+ process_sp->Destroy();
+ }
+ GetDebuggerSP()->DisconnectInput();
+ lldb_private::WillTerminate();
+ GetDebuggerSP().reset();
+ }
+}
+
+Debugger &
+Debugger::GetSharedInstance()
+{
+ // Don't worry about thread race conditions with the code below as
+ // lldb_private::Initialize(); does this in a thread safe way. I just
+ // want to avoid having to lock and unlock a mutex in
+ // lldb_private::Initialize(); every time we want to access the
+ // Debugger shared instance.
+
+ // FIXME: We intend to require clients to call Initialize by hand (since they
+ // will also have to call Terminate by hand.) But for now it is not clear where
+ // we can reliably call these in JH. So the present version initializes on first use
+ // here, and terminates in the destructor.
+ if (g_shared_debugger_refcount == 0 && !g_in_terminate)
+ Initialize();
+
+ assert(GetDebuggerSP().get()!= NULL);
+ return *(GetDebuggerSP().get());
+}
+
+Debugger::Debugger () :
+ m_input_comm("debugger.input"),
+ m_input_file (),
+ m_output_file (),
+ m_error_file (),
+ m_async_execution (true),
+ m_target_list (),
+ m_listener ("lldb.Debugger"),
+ m_source_manager (),
+ m_command_interpreter (eScriptLanguageDefault, false, &m_listener, m_source_manager),
+ m_input_readers (),
+ m_input_reader_data ()
+{
+}
+
+Debugger::~Debugger ()
+{
+ // FIXME:
+ // Remove this once this version of lldb has made its way through a build.
+ Terminate();
+}
+
+
+bool
+Debugger::GetAsyncExecution ()
+{
+ return m_async_execution;
+}
+
+void
+Debugger::SetAsyncExecution (bool async_execution)
+{
+ static bool value_has_been_set = false;
+
+ if (!value_has_been_set)
+ {
+ value_has_been_set = true;
+ m_async_execution = async_execution;
+ m_command_interpreter.SetSynchronous (!async_execution);
+ }
+}
+
+void
+Debugger::DisconnectInput()
+{
+ m_input_comm.Clear ();
+}
+
+void
+Debugger::SetInputFileHandle (FILE *fh, bool tranfer_ownership)
+{
+ m_input_file.SetFileHandle (fh, tranfer_ownership);
+ if (m_input_file.GetFileHandle() == NULL)
+ m_input_file.SetFileHandle (stdin, false);
+
+ // Disconnect from any old connection if we had one
+ m_input_comm.Disconnect ();
+ m_input_comm.SetConnection (new ConnectionFileDescriptor (::fileno (GetInputFileHandle()), true));
+ m_input_comm.SetReadThreadBytesReceivedCallback (Debugger::DispatchInputCallback, this);
+
+ Error error;
+ if (m_input_comm.StartReadThread (&error) == false)
+ {
+ FILE *err_fh = GetErrorFileHandle();
+ if (err_fh)
+ {
+ ::fprintf (err_fh, "error: failed to main input read thread: %s", error.AsCString() ? error.AsCString() : "unkown error");
+ exit(1);
+ }
+ }
+
+}
+
+FILE *
+Debugger::GetInputFileHandle ()
+{
+ return m_input_file.GetFileHandle();
+}
+
+
+void
+Debugger::SetOutputFileHandle (FILE *fh, bool tranfer_ownership)
+{
+ m_output_file.SetFileHandle (fh, tranfer_ownership);
+ if (m_output_file.GetFileHandle() == NULL)
+ m_output_file.SetFileHandle (stdin, false);
+}
+
+FILE *
+Debugger::GetOutputFileHandle ()
+{
+ return m_output_file.GetFileHandle();
+}
+
+void
+Debugger::SetErrorFileHandle (FILE *fh, bool tranfer_ownership)
+{
+ m_error_file.SetFileHandle (fh, tranfer_ownership);
+ if (m_error_file.GetFileHandle() == NULL)
+ m_error_file.SetFileHandle (stdin, false);
+}
+
+
+FILE *
+Debugger::GetErrorFileHandle ()
+{
+ return m_error_file.GetFileHandle();
+}
+
+CommandInterpreter &
+Debugger::GetCommandInterpreter ()
+{
+ return m_command_interpreter;
+}
+
+Listener &
+Debugger::GetListener ()
+{
+ return m_listener;
+}
+
+
+TargetSP
+Debugger::GetCurrentTarget ()
+{
+ return m_target_list.GetCurrentTarget ();
+}
+
+ExecutionContext
+Debugger::GetCurrentExecutionContext ()
+{
+ ExecutionContext exe_ctx;
+ exe_ctx.Clear();
+
+ lldb::TargetSP target_sp = GetCurrentTarget();
+ exe_ctx.target = target_sp.get();
+
+ if (target_sp)
+ {
+ exe_ctx.process = target_sp->GetProcessSP().get();
+ if (exe_ctx.process && exe_ctx.process->IsRunning() == false)
+ {
+ exe_ctx.thread = exe_ctx.process->GetThreadList().GetCurrentThread().get();
+ if (exe_ctx.thread == NULL)
+ exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get();
+ if (exe_ctx.thread)
+ {
+ exe_ctx.frame = exe_ctx.thread->GetCurrentFrame().get();
+ if (exe_ctx.frame == NULL)
+ exe_ctx.frame = exe_ctx.thread->GetStackFrameAtIndex (0).get();
+ }
+ }
+ }
+ return exe_ctx;
+
+}
+
+SourceManager &
+Debugger::GetSourceManager ()
+{
+ return m_source_manager;
+}
+
+
+TargetList&
+Debugger::GetTargetList ()
+{
+ return m_target_list;
+}
+
+void
+Debugger::DispatchInputCallback (void *baton, const void *bytes, size_t bytes_len)
+{
+ ((Debugger *)baton)->DispatchInput ((char *)bytes, bytes_len);
+}
+
+
+void
+Debugger::DispatchInput (const char *bytes, size_t bytes_len)
+{
+ if (bytes == NULL || bytes_len == 0)
+ return;
+
+ // TODO: implement the STDIO to the process as an input reader...
+ TargetSP target = GetCurrentTarget();
+ if (target.get() != NULL)
+ {
+ ProcessSP process_sp = target->GetProcessSP();
+ if (process_sp.get() != NULL
+ && StateIsRunningState (process_sp->GetState()))
+ {
+ Error error;
+ if (process_sp->PutSTDIN (bytes, bytes_len, error) == bytes_len)
+ return;
+ }
+ }
+
+ WriteToDefaultReader (bytes, bytes_len);
+}
+
+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_readers.empty() && !m_input_reader_data.empty())
+ {
+ while (CheckIfTopInputReaderIsDone ())
+ /* Do nothing. */;
+
+ // Get the input reader from the top of the stack
+ InputReaderSP reader_sp(m_input_readers.top());
+
+ if (!reader_sp)
+ break;
+
+ size_t bytes_handled = reader_sp->HandleRawBytes (m_input_reader_data.data(),
+ 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 donesvn
+ while (CheckIfTopInputReaderIsDone ())
+ /* Do nothing. */;
+
+}
+
+void
+Debugger::PushInputReader (const InputReaderSP& reader_sp)
+{
+ if (!reader_sp)
+ return;
+ if (!m_input_readers.empty())
+ {
+ // Deactivate the old top reader
+ InputReaderSP top_reader_sp (m_input_readers.top());
+ if (top_reader_sp)
+ top_reader_sp->Notify (eInputReaderDeactivate);
+ }
+ m_input_readers.push (reader_sp);
+ reader_sp->Notify (eInputReaderActivate);
+ ActivateInputReader (reader_sp);
+}
+
+bool
+Debugger::PopInputReader (const lldb::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_readers.empty())
+ {
+ InputReaderSP reader_sp(m_input_readers.top());
+
+ if (!pop_reader_sp || pop_reader_sp.get() == reader_sp.get())
+ {
+ m_input_readers.pop ();
+ reader_sp->Notify (eInputReaderDeactivate);
+ reader_sp->Notify (eInputReaderDone);
+ result = true;
+
+ if (!m_input_readers.empty())
+ {
+ reader_sp = m_input_readers.top();
+ if (reader_sp)
+ {
+ ActivateInputReader (reader_sp);
+ reader_sp->Notify (eInputReaderReactivate);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+bool
+Debugger::CheckIfTopInputReaderIsDone ()
+{
+ bool result = false;
+ if (!m_input_readers.empty())
+ {
+ InputReaderSP reader_sp(m_input_readers.top());
+
+ if (reader_sp && reader_sp->IsDone())
+ {
+ result = true;
+ PopInputReader (reader_sp);
+ }
+ }
+ return result;
+}
+
+void
+Debugger::ActivateInputReader (const InputReaderSP &reader_sp)
+{
+ FILE *in_fh = GetInputFileHandle();
+
+ if (in_fh)
+ {
+ struct termios in_fh_termios;
+ int in_fd = fileno (in_fh);
+ if (::tcgetattr(in_fd, &in_fh_termios) == 0)
+ {
+ if (reader_sp->GetEcho())
+ in_fh_termios.c_lflag |= ECHO; // Turn on echoing
+ else
+ in_fh_termios.c_lflag &= ~ECHO; // Turn off echoing
+
+ switch (reader_sp->GetGranularity())
+ {
+ case eInputReaderGranularityByte:
+ case eInputReaderGranularityWord:
+ in_fh_termios.c_lflag &= ~ICANON; // Get one char at a time
+ break;
+
+ case eInputReaderGranularityLine:
+ case eInputReaderGranularityAll:
+ in_fh_termios.c_lflag |= ICANON; // Get lines at a time
+ break;
+
+ default:
+ break;
+ }
+ ::tcsetattr (in_fd, TCSANOW, &in_fh_termios);
+ }
+ }
+}
diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp
new file mode 100644
index 00000000000..570ff726225
--- /dev/null
+++ b/lldb/source/Core/Disassembler.cpp
@@ -0,0 +1,299 @@
+//===-- 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/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/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Timer.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;
+
+
+Disassembler*
+Disassembler::FindPlugin (const ArchSpec &arch)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "Disassembler::FindPlugin (arch = %s)",
+ arch.AsCString());
+
+ std::auto_ptr<Disassembler> disassembler_ap;
+ DisassemblerCreateInstance create_callback;
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ disassembler_ap.reset (create_callback(arch));
+
+ if (disassembler_ap.get())
+ return disassembler_ap.release();
+ }
+ return NULL;
+}
+
+bool
+Disassembler::Disassemble
+(
+ const ArchSpec &arch,
+ const ExecutionContext &exe_ctx,
+ uint32_t mixed_context_lines,
+ Stream &strm
+)
+{
+ Disassembler *disassembler = Disassembler::FindPlugin(arch);
+
+ if (disassembler)
+ {
+ lldb::addr_t addr = LLDB_INVALID_ADDRESS;
+ size_t byte_size = 0;
+ if (exe_ctx.frame)
+ {
+ SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
+ if (sc.function)
+ {
+ addr = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(exe_ctx.process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ byte_size = sc.function->GetAddressRange().GetByteSize();
+ }
+ else if (sc.symbol && sc.symbol->GetAddressRangePtr())
+ {
+ addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetLoadAddress(exe_ctx.process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ {
+ byte_size = sc.symbol->GetAddressRangePtr()->GetByteSize();
+ if (byte_size == 0)
+ byte_size = DEFAULT_DISASM_BYTE_SIZE;
+ }
+ }
+ else
+ {
+ addr = exe_ctx.frame->GetPC().GetLoadAddress(exe_ctx.process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ byte_size = DEFAULT_DISASM_BYTE_SIZE;
+ }
+ }
+
+ if (byte_size)
+ {
+ DataExtractor data;
+ size_t bytes_disassembled = disassembler->ParseInstructions (&exe_ctx, eAddressTypeLoad, addr, byte_size, data);
+ if (bytes_disassembled == 0)
+ {
+ return false;
+ }
+ else
+ {
+ // We got some things disassembled...
+ size_t num_instructions = disassembler->GetInstructionList().GetSize();
+ uint32_t offset = 0;
+ SymbolContext sc;
+ SymbolContext prev_sc;
+ AddressRange sc_range;
+ if (mixed_context_lines)
+ strm.IndentMore ();
+
+ for (size_t i=0; i<num_instructions; ++i)
+ {
+ Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i);
+ if (inst)
+ {
+ lldb::addr_t curr_addr = addr + offset;
+ if (mixed_context_lines)
+ {
+ if (!sc_range.ContainsLoadAddress (curr_addr, exe_ctx.process))
+ {
+ prev_sc = sc;
+ Address curr_so_addr;
+ Process *process = exe_ctx.process;
+ if (process && process->ResolveLoadAddress (curr_addr, curr_so_addr))
+ {
+ if (curr_so_addr.GetSection())
+ {
+ Module *module = curr_so_addr.GetSection()->GetModule();
+ uint32_t resolved_mask = module->ResolveSymbolContextForAddress(curr_so_addr, eSymbolContextEverything, sc);
+ if (resolved_mask)
+ {
+ sc.GetAddressRange (eSymbolContextEverything, sc_range);
+ if (sc != prev_sc)
+ {
+ if (offset != 0)
+ strm.EOL();
+
+ sc.DumpStopContext(&strm, process, curr_so_addr);
+
+ if (sc.comp_unit && sc.line_entry.IsValid())
+ {
+ Debugger::GetSharedInstance().GetSourceManager().DisplaySourceLinesWithLineNumbers (
+ sc.line_entry.file,
+ sc.line_entry.line,
+ mixed_context_lines,
+ mixed_context_lines,
+ mixed_context_lines ? "->" : "",
+ &strm);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (mixed_context_lines)
+ strm.IndentMore ();
+ strm.Indent();
+ size_t inst_byte_size = inst->GetByteSize();
+ //inst->Dump(&strm, curr_addr, &data, offset); // Do dump opcode bytes
+ inst->Dump(&strm, curr_addr, NULL, offset, exe_ctx, false); // Don't dump opcode bytes
+ strm.EOL();
+ offset += inst_byte_size;
+ if (mixed_context_lines)
+ strm.IndentLess ();
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (mixed_context_lines)
+ strm.IndentLess ();
+
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+Disassembler::Instruction::Instruction()
+{
+}
+
+Disassembler::Instruction::~Instruction()
+{
+}
+
+
+Disassembler::InstructionList::InstructionList() :
+ m_instructions()
+{
+}
+
+Disassembler::InstructionList::~InstructionList()
+{
+}
+
+size_t
+Disassembler::InstructionList::GetSize() const
+{
+ return m_instructions.size();
+}
+
+
+Disassembler::Instruction *
+Disassembler::InstructionList::GetInstructionAtIndex (uint32_t idx)
+{
+ if (idx < m_instructions.size())
+ return m_instructions[idx].get();
+ return NULL;
+}
+
+const Disassembler::Instruction *
+Disassembler::InstructionList::GetInstructionAtIndex (uint32_t idx) const
+{
+ if (idx < m_instructions.size())
+ return m_instructions[idx].get();
+ return NULL;
+}
+
+void
+Disassembler::InstructionList::Clear()
+{
+ m_instructions.clear();
+}
+
+void
+Disassembler::InstructionList::AppendInstruction (Instruction::shared_ptr &inst_sp)
+{
+ if (inst_sp)
+ m_instructions.push_back(inst_sp);
+}
+
+
+size_t
+Disassembler::ParseInstructions
+(
+ const ExecutionContext *exe_ctx,
+ lldb::AddressType addr_type,
+ lldb::addr_t addr,
+ size_t byte_size,
+ DataExtractor& data
+)
+{
+ Process *process = exe_ctx->process;
+
+ if (process == NULL)
+ return 0;
+
+ DataBufferSP data_sp(new DataBufferHeap (byte_size, '\0'));
+
+ Error error;
+ if (process->GetTarget().ReadMemory (addr_type, addr, data_sp->GetBytes(), data_sp->GetByteSize(), error, NULL))
+ {
+ data.SetData(data_sp);
+ data.SetByteOrder(process->GetByteOrder());
+ data.SetAddressByteSize(process->GetAddressByteSize());
+ return ParseInstructions (data, 0, UINT32_MAX, addr);
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Disassembler copy constructor
+//----------------------------------------------------------------------
+Disassembler::Disassembler(const ArchSpec& arch) :
+ m_arch (arch),
+ m_instruction_list(),
+ m_base_addr(LLDB_INVALID_ADDRESS)
+{
+
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Disassembler::~Disassembler()
+{
+}
+
+Disassembler::InstructionList &
+Disassembler::GetInstructionList ()
+{
+ return m_instruction_list;
+}
+
+const Disassembler::InstructionList &
+Disassembler::GetInstructionList () const
+{
+ return m_instruction_list;
+}
diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp
new file mode 100644
index 00000000000..b6b2f27caef
--- /dev/null
+++ b/lldb/source/Core/DynamicLoader.cpp
@@ -0,0 +1,75 @@
+//===-- 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/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)
+ {
+ create_callback = PluginManager::GetDynamicLoaderCreateCallbackForPluginName (plugin_name);
+ if (create_callback)
+ {
+ std::auto_ptr<DynamicLoader> instance_ap(create_callback(process));
+ if (instance_ap.get())
+ return instance_ap.release();
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetDynamicLoaderCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ std::auto_ptr<DynamicLoader> instance_ap(create_callback(process));
+ if (instance_ap.get())
+ return instance_ap.release();
+ }
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// DynamicLoader constructor
+//----------------------------------------------------------------------
+DynamicLoader::DynamicLoader(Process *process) :
+ m_process (process),
+ m_stop_when_images_change(false) // Stop the process by default when a process' images change
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DynamicLoader::~DynamicLoader()
+{
+}
+
+//----------------------------------------------------------------------
+// Accessosors to the global setting as to wether to stop at image
+// (shared library) loading/unloading.
+//----------------------------------------------------------------------
+bool
+DynamicLoader::GetStopWhenImagesChange () const
+{
+ return m_stop_when_images_change;
+}
+
+void
+DynamicLoader::SetStopWhenImagesChange (bool stop)
+{
+ m_stop_when_images_change = stop;
+}
+
diff --git a/lldb/source/Core/Error.cpp b/lldb/source/Core/Error.cpp
new file mode 100644
index 00000000000..c3522093f9b
--- /dev/null
+++ b/lldb/source/Core/Error.cpp
@@ -0,0 +1,365 @@
+//===-- 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 <sys/errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+
+#if defined (__arm__)
+#include <SpringBoardServices/SpringBoardServer.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+Error::Error(ValueType err, ErrorType type) :
+ m_code (err),
+ m_type (type),
+ m_string ()
+{
+}
+//----------------------------------------------------------------------
+// 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 = (kern_return_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:
+ s = ::mach_error_string (m_code);
+ 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::SetError (kern_return_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;
+ m_string.append("\n");
+ }
+ 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...
+ m_string.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);
+ int length = ::vsnprintf (&m_string[0], m_string.size(), format, args);
+ if (length < m_string.size())
+ {
+ // The error formatted string fit into our buffer, just chop it down
+ // to size
+ m_string.erase (length);
+ }
+ else
+ {
+ // The error formatted string didn't fit into our buffer, resize it
+ // to the exact needed size, and retry
+ m_string.resize(length + 1);
+ length = ::vsnprintf (&m_string[0], m_string.size(), format, copy_args);
+ va_end (copy_args);
+ assert (length < m_string.size());
+ }
+ 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;
+}
diff --git a/lldb/source/Core/Event.cpp b/lldb/source/Core/Event.cpp
new file mode 100644
index 00000000000..c2bf08d8deb
--- /dev/null
+++ b/lldb/source/Core/Event.cpp
@@ -0,0 +1,241 @@
+//===-- 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/Target/Process.h"
+
+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::Clear()
+{
+ m_data_ap.reset();
+}
+
+void
+Event::Dump (Stream *s) const
+{
+ s->Printf("%p Event: broadcaster = %p, type = 0x%8.8x, data = ", this, m_broadcaster, m_type);
+
+ if (m_data_ap.get() == NULL)
+ s->Printf ("<NULL>");
+ else
+ {
+ s->PutChar('{');
+ m_data_ap->Dump (s);
+ s->PutChar('}');
+ }
+}
+
+Broadcaster *
+Event::GetBroadcaster () const
+{
+ return m_broadcaster;
+}
+
+bool
+Event::BroadcasterIs (Broadcaster *broadcaster)
+{
+ return broadcaster == m_broadcaster;
+}
+
+uint32_t
+Event::GetType() const
+{
+ return m_type;
+}
+
+
+EventData *
+Event::GetData ()
+{
+ return m_data_ap.get();
+}
+
+const EventData *
+Event::GetData () const
+{
+ return m_data_ap.get();
+}
+
+void
+Event::DoOnRemoval ()
+{
+ if (m_data_ap.get())
+ m_data_ap->DoOnRemoval (this);
+}
+
+void
+Event::SetBroadcaster (Broadcaster *broadcaster)
+{
+ m_broadcaster = broadcaster;
+}
+
+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
+ {
+ DataExtractor data;
+ data.SetData(m_bytes.data(), m_bytes.size(), eByteOrderHost);
+ 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.data();
+}
+
+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;
+}
+
diff --git a/lldb/source/Core/FileSpec.cpp b/lldb/source/Core/FileSpec.cpp
new file mode 100644
index 00000000000..305650d8643
--- /dev/null
+++ b/lldb/source/Core/FileSpec.cpp
@@ -0,0 +1,580 @@
+//===-- 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 <fcntl.h>
+#include <glob.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <fstream>
+
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataBufferMemoryMap.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+static bool
+GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
+{
+ char resolved_path[PATH_MAX];
+ if (file_spec->GetPath(&resolved_path[0], sizeof(resolved_path)))
+ return ::stat (resolved_path, stats_ptr) == 0;
+ return false;
+}
+
+static const char*
+GetCachedGlobTildeSlash()
+{
+ static std::string g_tilde;
+ if (g_tilde.empty())
+ {
+ glob_t globbuf;
+ if (::glob("~/", GLOB_TILDE, NULL, &globbuf) == 0) //success
+ {
+ g_tilde = globbuf.gl_pathv[0];
+ ::globfree (&globbuf);
+ }
+ if (g_tilde.empty())
+ return NULL;
+ }
+ return g_tilde.c_str();
+}
+
+int
+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];
+ if (::strstr (src_path, "~/") == src_path)
+ ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s%s", GetCachedGlobTildeSlash(), src_path + 2);
+ else
+ ::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) :
+ m_directory(),
+ m_filename()
+{
+ if (pathname && pathname[0])
+ SetFile(pathname);
+}
+
+//------------------------------------------------------------------
+// Copy constructor
+//------------------------------------------------------------------
+FileSpec::FileSpec(const FileSpec& rhs) :
+ m_directory (rhs.m_directory),
+ m_filename (rhs.m_filename)
+{
+}
+
+//------------------------------------------------------------------
+// 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;
+ }
+ 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)
+{
+ m_filename.Clear();
+ m_directory.Clear();
+ if (pathname == NULL || pathname[0] == '\0')
+ return;
+
+ char resolved_path[PATH_MAX];
+
+ if (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1)
+ {
+ 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
+void*() const
+{
+ return (m_directory || m_filename) ? const_cast<FileSpec*>(this) : NULL;
+}
+
+//----------------------------------------------------------------------
+// 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
+{
+ return m_directory == rhs.m_directory && m_filename == rhs.m_filename;
+}
+
+//------------------------------------------------------------------
+// Not equal to operator
+//------------------------------------------------------------------
+bool
+FileSpec::operator!= (const FileSpec& rhs) const
+{
+ return m_filename != rhs.m_filename || m_directory != rhs.m_directory;
+}
+
+//------------------------------------------------------------------
+// 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)
+ return a == b;
+ else
+ return a.m_filename == b.m_filename;
+}
+
+
+
+//------------------------------------------------------------------
+// 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
+{
+ if (m_filename)
+ m_directory.Dump(s, ""); // Provide a default for m_directory when we dump it in case it is invalid
+
+ if (m_directory)
+ {
+ // If dirname was valid, then we need to print a slash between
+ // the directory and the filename
+ 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);
+}
+
+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 eFileTypeUknown;
+ }
+ return eFileTypeInvalid;
+}
+
+TimeValue
+FileSpec::GetModificationTime () const
+{
+ TimeValue mod_time;
+ struct stat file_stats;
+ if (GetFileStats (this, &file_stats))
+ mod_time = file_stats.st_mtimespec;
+ 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.
+//------------------------------------------------------------------
+bool
+FileSpec::GetPath(char *path, size_t max_path_length) const
+{
+ if (max_path_length == 0)
+ return false;
+
+ path[0] = '\0';
+ const char *dirname = m_directory.AsCString();
+ const char *filename = m_filename.AsCString();
+ if (dirname)
+ {
+ if (filename && filename[0])
+ {
+ return snprintf (path, max_path_length, "%s/%s", dirname, filename) < max_path_length;
+ }
+ else
+ {
+ strncpy (path, dirname, max_path_length);
+ }
+ }
+ else if (filename)
+ {
+ strncpy (path, filename, max_path_length);
+ }
+
+ // Any code paths that reach here assume that strncpy, or a similar function was called
+ // where any remaining bytes will be filled with NULLs and that the string won't be
+ // NULL terminated if it won't fit in the buffer.
+
+ // If the last character is NULL, then all went well
+ if (path[max_path_length-1] == '\0')
+ return true;
+
+ // Make sure the path is terminated, as it didn't fit into "path"
+ path[max_path_length-1] = '\0';
+ return false;
+}
+
+//------------------------------------------------------------------
+// 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;
+ auto_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap());
+ if (mmap_data.get())
+ {
+ if (mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size) >= 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();
+}
+
+//------------------------------------------------------------------
+// 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) const
+{
+ DataBufferSP data_sp;
+ char resolved_path[PATH_MAX];
+ if (GetPath(resolved_path, sizeof(resolved_path)))
+ {
+ int fd = ::open (resolved_path, O_RDONLY, 0);
+ if (fd != -1)
+ {
+ struct stat file_stats;
+ if (::fstat (fd, &file_stats) == 0)
+ {
+ // Read bytes directly into our basic_string buffer
+ if (file_stats.st_size > 0)
+ {
+ off_t lseek_result = 0;
+ if (file_offset > 0)
+ lseek_result = ::lseek (fd, file_offset, SEEK_SET);
+
+ if (lseek_result < 0)
+ {
+ // Get error from errno
+ }
+ else if (lseek_result == file_offset)
+ {
+ std::auto_ptr<DataBufferHeap> data_heap_ap;
+ if (file_stats.st_size < file_size)
+ data_heap_ap.reset(new DataBufferHeap(file_stats.st_size, '\0'));
+ else
+ data_heap_ap.reset(new DataBufferHeap(file_size, '\0'));
+
+ if (data_heap_ap.get())
+ {
+ ssize_t bytesRead = ::read (fd, (void *)data_heap_ap->GetBytes(), data_heap_ap->GetByteSize());
+ if (bytesRead >= 0)
+ {
+ // Make sure we read exactly what we asked for and if we got
+ // less, adjust the array
+ if (bytesRead < data_heap_ap->GetByteSize())
+ data_heap_ap->SetByteSize(bytesRead);
+ data_sp.reset(data_heap_ap.release());
+ }
+ }
+ }
+ }
+ }
+ }
+ close(fd);
+ }
+ return data_sp;
+}
+
+bool
+FileSpec::ReadFileLines (STLStringArray &lines)
+{
+ bool ret_val = false;
+ lines.clear();
+
+ std::string dir_str (m_directory.AsCString());
+ std::string file_str (m_filename.AsCString());
+ std::string full_name = dir_str + "/" + file_str;
+
+ ifstream file_stream (full_name.c_str());
+
+ if (file_stream)
+ {
+ std::string line;
+ while (getline (file_stream, line))
+ lines.push_back (line);
+ ret_val = true;
+ }
+
+ return ret_val;
+}
diff --git a/lldb/source/Core/FileSpecList.cpp b/lldb/source/Core/FileSpecList.cpp
new file mode 100644
index 00000000000..17abf4b24e5
--- /dev/null
+++ b/lldb/source/Core/FileSpecList.cpp
@@ -0,0 +1,228 @@
+//===-- 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"
+
+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
+{
+ for_each (m_files.begin(), m_files.end(), bind2nd(mem_fun_ref(&FileSpec::Dump),s));
+}
+
+//------------------------------------------------------------------
+// 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.
+//------------------------------------------------------------------
+uint32_t
+FileSpecList::FindFileIndex (uint32_t start_idx, const FileSpec &file_spec) const
+{
+ const uint32_t num_files = m_files.size();
+ uint32_t idx;
+
+ // 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 (idx = start_idx; idx < num_files; ++idx)
+ {
+ if (compare_filename_only)
+ {
+ if (m_files[idx].GetFilename() == file_spec.GetFilename())
+ return idx;
+ }
+ else
+ {
+ if (m_files[idx] == file_spec)
+ 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(uint32_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(uint32_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.
+//------------------------------------------------------------------
+uint32_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/lldb/source/Core/Flags.cpp b/lldb/source/Core/Flags.cpp
new file mode 100644
index 00000000000..13cbd85915b
--- /dev/null
+++ b/lldb/source/Core/Flags.cpp
@@ -0,0 +1,122 @@
+//===-- Flags.cpp -----------------------------------------------*- 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/Flags.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default Constructor
+//----------------------------------------------------------------------
+Flags::Flags (ValueType flags) :
+ m_flags(flags)
+{
+}
+
+//----------------------------------------------------------------------
+// Copy Constructor
+//----------------------------------------------------------------------
+Flags::Flags (const Flags& rhs) :
+ m_flags(rhs.m_flags)
+{
+}
+
+//----------------------------------------------------------------------
+// Virtual destructor in case anyone inherits from this class.
+//----------------------------------------------------------------------
+Flags::~Flags ()
+{
+}
+
+//----------------------------------------------------------------------
+// Get accessor for all of the current flag bits.
+//----------------------------------------------------------------------
+Flags::ValueType
+Flags::GetAllFlagBits () const
+{
+ return m_flags;
+}
+
+size_t
+Flags::GetBitSize() const
+{
+ return sizeof (ValueType) * 8;
+}
+
+//----------------------------------------------------------------------
+// Set accessor for all of the current flag bits.
+//----------------------------------------------------------------------
+void
+Flags::SetAllFlagBits (ValueType flags)
+{
+ m_flags = flags;
+}
+
+//----------------------------------------------------------------------
+// Clear one or more bits in our flag bits
+//----------------------------------------------------------------------
+Flags::ValueType
+Flags::Clear (ValueType bits)
+{
+ m_flags &= ~bits;
+ return m_flags;
+}
+
+//----------------------------------------------------------------------
+// Set one or more bits in our flag bits
+//----------------------------------------------------------------------
+Flags::ValueType
+Flags::Set (ValueType bits)
+{
+ m_flags |= bits;
+ return m_flags;
+}
+
+//----------------------------------------------------------------------
+// Returns true if any flag bits in "bits" are set
+//----------------------------------------------------------------------
+bool
+Flags::IsSet (ValueType bits) const
+{
+ return (m_flags & bits) != 0;
+}
+
+//----------------------------------------------------------------------
+// Returns true if all flag bits in "bits" are clear
+//----------------------------------------------------------------------
+bool
+Flags::IsClear (ValueType bits) const
+{
+ return (m_flags & bits) == 0;
+}
+
+
+size_t
+Flags::SetCount () const
+{
+ size_t count = 0;
+ for (ValueType mask = m_flags; mask; mask >>= 1)
+ {
+ if (mask & 1)
+ ++count;
+ }
+ return count;
+}
+
+size_t
+Flags::ClearCount () const
+{
+ size_t count = 0;
+ for (ValueType shift = 0; shift < sizeof(ValueType)*8; ++shift)
+ {
+ if ((m_flags & (1u << shift)) == 0)
+ ++count;
+ }
+ return count;
+}
diff --git a/lldb/source/Core/InputReader.cpp b/lldb/source/Core/InputReader.cpp
new file mode 100644
index 00000000000..c139a87387a
--- /dev/null
+++ b/lldb/source/Core/InputReader.cpp
@@ -0,0 +1,343 @@
+//===-- 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 <string>
+
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Debugger.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+InputReader::InputReader () :
+ m_callback (NULL),
+ m_callback_baton (NULL),
+ m_end_token (),
+ m_granularity (eInputReaderGranularityInvalid),
+ m_done (true),
+ m_echo (true),
+ m_active (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)
+ {
+ 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;
+ const char *end = bytes + bytes_len;
+ 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;
+}
+
+
+FILE *
+InputReader::GetInputFileHandle ()
+{
+ return Debugger::GetSharedInstance().GetInputFileHandle ();
+}
+
+FILE *
+InputReader::GetOutputFileHandle ()
+{
+ return Debugger::GetSharedInstance().GetOutputFileHandle ();
+}
+
+const char *
+InputReader::GetPrompt () const
+{
+ if (!m_prompt.empty())
+ return m_prompt.c_str();
+ else
+ return NULL;
+}
+
+void
+InputReader::RefreshPrompt ()
+{
+ if (!m_prompt.empty())
+ {
+ FILE *out_fh = GetOutputFileHandle();
+ if (out_fh)
+ ::fprintf (out_fh, "%s", m_prompt.c_str());
+ }
+}
+
+void
+InputReader::Notify (InputReaderAction notification)
+{
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ case eInputReaderReactivate:
+ m_active = true;
+ break;
+
+ case eInputReaderDeactivate:
+ case eInputReaderDone:
+ m_active = false;
+ 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);
+}
diff --git a/lldb/source/Core/Language.cpp b/lldb/source/Core/Language.cpp
new file mode 100644
index 00000000000..82b4e4f3aca
--- /dev/null
+++ b/lldb/source/Core/Language.cpp
@@ -0,0 +1,150 @@
+//===-- 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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define ENUM_TO_DCSTREAM(x) case x: s->PutCString(#x); return
+
+typedef 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 uint32_t
+g_num_languages = sizeof(g_languages)/sizeof(LanguageStrings);
+
+Language::Language(Language::Type language) :
+ m_language (language)
+{
+}
+
+Language::~Language()
+{
+}
+
+Language::Type
+Language::GetLanguage() const
+{
+ return m_language;
+}
+
+void
+Language::Clear ()
+{
+ m_language = Unknown;
+}
+
+void
+Language::SetLanguage(Language::Type 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 = (Language::Type)i;
+ return true;
+ }
+ }
+ }
+
+ m_language = Unknown;
+ 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/lldb/source/Core/Listener.cpp b/lldb/source/Core/Listener.cpp
new file mode 100644
index 00000000000..639b74a4c7d
--- /dev/null
+++ b/lldb/source/Core/Listener.cpp
@@ -0,0 +1,480 @@
+//===-- 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"
+
+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);
+ 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();
+}
+
+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::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 (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.Reset();
+ 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)
+ {
+ 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
+ m_cond_wait.SetValue (false, eBroadcastNever);
+
+ if (m_cond_wait.WaitForValueEqualTo (true, timeout, &timed_out))
+ continue;
+
+ else if (timed_out)
+ {
+ if (log)
+ log->Printf ("%p Listener::WaitForEvents() timed out for %s", this, m_name.c_str());
+ break;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("%p Listener::WaitForEvents() 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;
+}
diff --git a/lldb/source/Core/Log.cpp b/lldb/source/Core/Log.cpp
new file mode 100644
index 00000000000..fe2071683ca
--- /dev/null
+++ b/lldb/source/Core/Log.cpp
@@ -0,0 +1,590 @@
+//===-- Log.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 <mach/mach.h>
+#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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static Stream *
+StreamForSTDOUTAccess (bool set, StreamSP &stream_sp)
+{
+ // Since we are in a shared library and we can't have global
+ // constructors, we need to control access to this static variable
+ // through an accessor function to get and set the value.
+ static StreamSP g_stream_sp;
+
+ if (set)
+ g_stream_sp = stream_sp;
+ else
+ {
+ if (g_stream_sp)
+ stream_sp = g_stream_sp;
+ else
+ {
+ FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle();
+ if (out_fh)
+ stream_sp.reset(new StreamFile(out_fh));
+ else
+ stream_sp.reset();
+ }
+ }
+ return stream_sp.get();
+}
+
+StreamSP
+Log::GetStreamForSTDOUT ()
+{
+ StreamSP stream_sp;
+ StreamForSTDOUTAccess (false, stream_sp);
+ return stream_sp;
+}
+
+void
+Log::SetStreamForSTDOUT (StreamSP &stream_sp)
+{
+ StreamForSTDOUTAccess (true, stream_sp);
+}
+
+void
+Log::STDOUT (const char *format, ...)
+{
+ StreamSP stream_sp;
+ if (StreamForSTDOUTAccess(false, stream_sp))
+ {
+ va_list args;
+ va_start (args, format);
+ stream_sp->PrintfVarArg(format, args);
+ va_end (args);
+ }
+}
+
+static Stream *
+StreamForSTDERRAccess (bool set, StreamSP &stream_sp)
+{
+ // Since we are in a shared library and we can't have global
+ // constructors, we need to control access to this static variable
+ // through an accessor function to get and set the value.
+ static StreamSP g_stream_sp(new StreamFile(Debugger::GetSharedInstance().GetErrorFileHandle()));
+
+ if (set)
+ g_stream_sp = stream_sp;
+ else
+ stream_sp = g_stream_sp;
+ return stream_sp.get();
+}
+
+StreamSP
+Log::GetStreamForSTDERR ()
+{
+ StreamSP stream_sp;
+ StreamForSTDERRAccess (false, stream_sp);
+ return stream_sp;
+}
+
+void
+Log::SetStreamForSTDERR (StreamSP &stream_sp)
+{
+ StreamForSTDERRAccess (true, stream_sp);
+}
+
+void
+Log::STDERR (const char *format, ...)
+{
+ StreamSP stream_sp;
+ if (StreamForSTDERRAccess(false, stream_sp))
+ {
+ va_list args;
+ va_start (args, format);
+ stream_sp->PrintfVarArg(format, args);
+ va_end (args);
+ }
+}
+
+Log::Log () :
+ m_stream_sp(),
+ m_options(0),
+ m_mask_bits(0)
+{
+}
+
+Log::Log (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;
+ static Mutex g_LogThreadedMutex(Mutex::eMutexTypeRecursive);
+
+ Mutex::Locker locker;
+
+ uint32_t log_options = m_options.GetAllFlagBits();
+
+ // Lock the threaded logging mutex if we are doing thread safe logging
+ if (log_options & LLDB_LOG_OPTION_THREADSAFE)
+ locker.Reset(g_LogThreadedMutex.GetMutex());
+
+ // Add a sequence ID if requested
+ if (log_options & LLDB_LOG_OPTION_PREPEND_SEQUENCE)
+ header.Printf ("%u ", ++g_sequence_id);
+
+ // Timestamp if requested
+ if (log_options & LLDB_LOG_OPTION_PREPEND_TIMESTAMP)
+ {
+ struct timeval tv = TimeValue::Now().GetAsTimeVal();
+ header.Printf ("%9llu.%6.6llu ", tv.tv_sec, tv.tv_usec);
+ }
+
+ // Add the process and thread if requested
+ if (log_options & LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD)
+ header.Printf ("[%4.4x/%4.4x]: ", getpid(), mach_thread_self());
+
+ // Add the process and thread if requested
+ if (log_options & LLDB_LOG_OPTION_PREPEND_THREAD_NAME)
+ {
+ const char *thread_name_str = Host::GetThreadName (getpid(), mach_thread_self());
+ if (thread_name_str)
+ header.Printf ("%s ", thread_name_str);
+ }
+
+ header.PrintfVarArg (format, args);
+ m_stream_sp->Printf("%s\n", header.GetData());
+ }
+}
+
+
+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().IsSet(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().IsSet(LLDB_LOG_OPTION_DEBUG) && GetOptions().IsSet(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 ((bits & m_options.GetAllFlagBits()) == 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.IsSet(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.IsSet(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 <std::string, 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 char *channel, const Log::Callbacks &log_callbacks)
+{
+ GetCallbackMap().insert(std::make_pair(channel, log_callbacks));
+}
+
+bool
+Log::UnregisterLogChannel (const char *channel)
+{
+ return GetCallbackMap().erase(channel) != 0;
+}
+
+bool
+Log::GetLogChannelCallbacks (const char *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;
+ }
+ ::bzero (&log_callbacks, sizeof(log_callbacks));
+ return false;
+}
+
+void
+Log::EnableAllLogChannels
+(
+ StreamSP &log_stream_sp,
+ uint32_t log_options,
+ Args &args,
+ 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, args, 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, args);
+ }
+
+}
+
+void
+Log::DisableAllLogChannels ()
+{
+ CallbackMap &callback_map = GetCallbackMap ();
+ CallbackMapIter pos, end = callback_map.end();
+
+ for (pos = callback_map.begin(); pos != end; ++pos)
+ pos->second.disable ();
+
+ 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 ();
+}
+
+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
+{
+ 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())
+ {
+ LogChannelCreateInstance create_callback = PluginManager::GetLogChannelCreateCallbackForPluginName (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_sp ()
+{
+}
+
+LogChannel::~LogChannel ()
+{
+}
+
+const char *
+LogChannel::GetPluginSuffix ()
+{
+ return ".log-channel";
+}
+
+
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
new file mode 100644
index 00000000000..38667a86def
--- /dev/null
+++ b/lldb/source/Core/Mangled.cpp
@@ -0,0 +1,733 @@
+//===-- Mangled.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cxxabi.h>
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+
+using namespace lldb_private;
+
+#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 char *s, bool mangled) :
+ m_mangled(),
+ m_demangled()
+{
+ if (s && s[0])
+ {
+ SetValue(s, mangled);
+ }
+}
+
+//----------------------------------------------------------------------
+// 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(), a.GetName());
+}
+
+
+
+//----------------------------------------------------------------------
+// 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 char *s, bool mangled)
+{
+ m_mangled.Clear();
+ m_demangled.Clear();
+
+ if (s)
+ {
+ if (mangled)
+ m_mangled.SetCString (s);
+ else
+ m_demangled.SetCString(s);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// 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());
+
+ // We already know mangled is valid from the above check,
+ // lets just make sure it isn't empty...
+ const char * mangled = m_mangled.AsCString();
+ if (mangled[0])
+ {
+ // The first time the demangling routine is called, it will
+ // return a buffer value and length and we will continue to
+ // re-use that buffer so we don't always have to malloc/free
+ // a buffer for each demangle. The buffer can be realloc'ed
+ // by abi::__cxa_demangle, so we may need to make it thread
+ // specific if we ever start doing multi-threaded calls to
+ // this function. g_demangle_buf will currently leak one
+ // malloc entry that can vary in size. If we need to reclaim
+ // this memory, we will need to add some code to free this
+ // buffer at exit time.
+ static char *g_demangle_buf = NULL;
+ static size_t g_demangle_buf_len = 0;
+ int status = 0;
+ g_demangle_buf = abi::__cxa_demangle(mangled, g_demangle_buf, &g_demangle_buf_len, &status);
+ if (g_demangle_buf != NULL)
+ {
+ m_demangled.SetCString(g_demangle_buf);
+ }
+ else
+ {
+ // Set the demangled string to the empty string to indicate we
+ // tried to parse it once and failed.
+ m_demangled.SetCString("");
+ }
+ }
+ }
+
+ return m_demangled;
+}
+
+//----------------------------------------------------------------------
+// Mangled name get accessor
+//----------------------------------------------------------------------
+ConstString&
+Mangled::GetMangledName ()
+{
+ return m_mangled;
+}
+
+//----------------------------------------------------------------------
+// Mangled name const get accessor
+//----------------------------------------------------------------------
+const ConstString&
+Mangled::GetMangledName () const
+{
+ return m_mangled;
+}
+
+//----------------------------------------------------------------------
+// Get the demangled name if there is one, else return the mangled name.
+//----------------------------------------------------------------------
+const ConstString&
+Mangled::GetName () const
+{
+ const ConstString& name = GetDemangledName();
+ if (name && !name.IsEmpty())
+ return name;
+ return m_mangled;
+}
+
+//----------------------------------------------------------------------
+// Generate the tokens from the demangled name.
+//
+// Returns the number of tokens that were parsed.
+//----------------------------------------------------------------------
+size_t
+Mangled::GetTokens (Mangled::TokenList &tokens) const
+{
+ tokens.Clear();
+ const ConstString& demangled = GetDemangledName();
+ if (demangled && !demangled.IsEmpty())
+ tokens.Parse(demangled.AsCString());
+
+ return tokens.Size();
+}
+
+//----------------------------------------------------------------------
+// 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;
+}
+
+
+
+
+#pragma mark Mangled::Token
+
+//--------------------------------------------------------------
+// Default constructor
+//--------------------------------------------------------------
+Mangled::Token::Token () :
+ type(eInvalid),
+ value()
+{
+}
+
+//--------------------------------------------------------------
+// Equal to operator
+//--------------------------------------------------------------
+bool
+Mangled::Token::operator== (const Token& rhs) const
+{
+ return type == rhs.type && value == rhs.value;
+}
+
+//--------------------------------------------------------------
+// Dump the token to a stream "s"
+//--------------------------------------------------------------
+void
+Mangled::Token::Dump (Stream *s) const
+{
+ switch (type)
+ {
+ case eInvalid: s->PutCString("invalid "); break;
+ case eNameSpace: s->PutCString("namespace "); break;
+ case eMethodName: s->PutCString("method "); break;
+ case eType: s->PutCString("type "); break;
+ case eTemplate: s->PutCString("template "); break;
+ case eTemplateBeg: s->PutCString("template < "); break;
+ case eTemplateEnd: s->PutCString("template > "); break;
+ case eParamsBeg: s->PutCString("params ( "); break;
+ case eParamsEnd: s->PutCString("params ) "); break;
+ case eQualifier: s->PutCString("qualifier "); break;
+ case eError: s->PutCString("ERROR "); break;
+ default:
+ s->Printf("type = %i", type);
+ break;
+ }
+ value.DumpDebug(s);
+}
+
+//--------------------------------------------------------------
+// Returns true if this token is a wildcard
+//--------------------------------------------------------------
+bool
+Mangled::Token::IsWildcard () const
+{
+ static ConstString g_wildcard_str("*");
+ return value == g_wildcard_str;
+}
+
+
+//----------------------------------------------------------------------
+// Dump "obj" to the supplied stream "s"
+//----------------------------------------------------------------------
+Stream&
+lldb_private::operator << (Stream& s, const Mangled::Token& obj)
+{
+ obj.Dump(&s);
+ return s;
+}
+
+
+#pragma mark Mangled::TokenList
+//----------------------------------------------------------------------
+// Mangled::TokenList
+//----------------------------------------------------------------------
+
+//--------------------------------------------------------------
+// Default constructor. If demangled is non-NULL and not-empty
+// the token list will parse up the demangled string it is
+// given, else the object will initialize an empty token list.
+//--------------------------------------------------------------
+Mangled::TokenList::TokenList (const char *demangled) :
+ m_tokens()
+{
+ if (demangled && demangled[0])
+ {
+ Parse(demangled);
+ }
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Mangled::TokenList::~TokenList ()
+{
+}
+
+//----------------------------------------------------------------------
+// Parses "demangled" into tokens. This allows complex
+// comparisons to be done. Comparisons can include wildcards at
+// the namespace, method name, template, and template and
+// parameter type levels.
+//
+// Example queries include:
+// "std::basic_string<*>" // Find all std::basic_string variants
+// "std::basic_string<*>::erase(*)" // Find all std::basic_string::erase variants with any number of parameters
+// "*::clear()" // Find all functions with a method name of
+// // "clear" that are in any namespace that
+// // have no parameters
+// "::printf" // Find the printf function in the global namespace
+// "printf" // Ditto
+// "foo::*(int)" // Find all functions in the class or namespace "foo" that take a single integer argument
+//
+// Returns the number of tokens that were decoded, or zero when
+// we fail.
+//----------------------------------------------------------------------
+size_t
+Mangled::TokenList::Parse (const char *s)
+{
+ m_tokens.clear();
+
+ Token token;
+ token.type = eNameSpace;
+
+ TokenType max_type = eInvalid;
+ const char *p = s;
+ size_t span = 0;
+ size_t sep_size = 0;
+
+ while (*p != '\0')
+ {
+ p = p + span + sep_size;
+ while (isspace(*p))
+ ++p;
+
+ if (*p == '\0')
+ break;
+
+ span = strcspn(p, ":<>(),");
+ sep_size = 1;
+ token.type = eInvalid;
+ switch (p[span])
+ {
+ case '\0':
+ break;
+
+ case ':':
+ if (p[span+1] == ':')
+ {
+ sep_size = 2;
+ if (span > 0)
+ {
+ token.type = eNameSpace;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+ else
+ continue;
+ }
+ break;
+
+ case '(':
+ if (span > 0)
+ {
+ token.type = eMethodName;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+
+ token.type = eParamsBeg;
+ token.value.Clear();
+ m_tokens.push_back(token);
+ break;
+
+ case ',':
+ if (span > 0)
+ {
+ token.type = eType;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+ else
+ {
+ continue;
+ }
+ break;
+
+ case ')':
+ if (span > 0)
+ {
+ token.type = eType;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+
+ token.type = eParamsEnd;
+ token.value.Clear();
+ m_tokens.push_back(token);
+ break;
+
+ case '<':
+ if (span > 0)
+ {
+ token.type = eTemplate;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+
+ token.type = eTemplateBeg;
+ token.value.Clear();
+ m_tokens.push_back(token);
+ break;
+
+ case '>':
+ if (span > 0)
+ {
+ token.type = eType;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+
+ token.type = eTemplateEnd;
+ token.value.Clear();
+ m_tokens.push_back(token);
+ break;
+ }
+
+ if (max_type < token.type)
+ max_type = token.type;
+
+ if (token.type == eInvalid)
+ {
+ if (max_type >= eParamsEnd)
+ {
+ token.type = eQualifier;
+ token.value.SetCString(p);
+ m_tokens.push_back(token);
+ }
+ else if (max_type >= eParamsBeg)
+ {
+ token.type = eType;
+ token.value.SetCString(p);
+ m_tokens.push_back(token);
+ }
+ else
+ {
+ token.type = eMethodName;
+ token.value.SetCString(p);
+ m_tokens.push_back(token);
+ }
+ break;
+ }
+ }
+ return m_tokens.size();
+}
+
+
+//----------------------------------------------------------------------
+// Clear the token list.
+//----------------------------------------------------------------------
+void
+Mangled::TokenList::Clear ()
+{
+ m_tokens.clear();
+}
+
+//----------------------------------------------------------------------
+// Dump the token list to the stream "s"
+//----------------------------------------------------------------------
+void
+Mangled::TokenList::Dump (Stream *s) const
+{
+ collection::const_iterator pos;
+ collection::const_iterator beg = m_tokens.begin();
+ collection::const_iterator end = m_tokens.end();
+ for (pos = beg; pos != end; ++pos)
+ {
+ s->Indent("token[");
+ *s << (uint32_t)std::distance(beg, pos) << "] = " << *pos << "\n";
+ }
+}
+
+//----------------------------------------------------------------------
+// Find the first token in the list that has "token_type" as its
+// type
+//----------------------------------------------------------------------
+const Mangled::Token *
+Mangled::TokenList::Find (TokenType token_type) const
+{
+ collection::const_iterator pos;
+ collection::const_iterator beg = m_tokens.begin();
+ collection::const_iterator end = m_tokens.end();
+ for (pos = beg; pos != end; ++pos)
+ {
+ if (pos->type == token_type)
+ return &(*pos);
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Return the token at index "idx", or NULL if the index is
+// out of range.
+//----------------------------------------------------------------------
+const Mangled::Token *
+Mangled::TokenList::GetTokenAtIndex (uint32_t idx) const
+{
+ if (idx < m_tokens.size())
+ return &m_tokens[idx];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Given a token list, see if it matches this object's tokens.
+// "token_list" can contain wild card values to enable powerful
+// matching. Matching the std::string::erase(*) example that was
+// tokenized above we could use a token list such as:
+//
+// token name
+// ----------- ----------------------------------------
+// eNameSpace "std"
+// eTemplate "basic_string"
+// eTemplateBeg
+// eInvalid "*"
+// eTemplateEnd
+// eMethodName "erase"
+// eParamsBeg
+// eInvalid "*"
+// eParamsEnd
+//
+// Returns true if it "token_list" matches this object's tokens,
+// false otherwise.
+//----------------------------------------------------------------------
+bool
+Mangled::TokenList::MatchesQuery (const Mangled::TokenList &match) const
+{
+ size_t match_count = 0;
+ collection::const_iterator pos;
+ collection::const_iterator pos_end = m_tokens.end();
+
+ collection::const_iterator match_pos;
+ collection::const_iterator match_pos_end = match.m_tokens.end();
+ collection::const_iterator match_wildcard_pos = match_pos_end;
+ collection::const_iterator match_next_pos = match_pos_end;
+
+ size_t template_scope_depth = 0;
+
+ for (pos = m_tokens.begin(), match_pos = match.m_tokens.begin();
+ pos != pos_end && match_pos != match_pos_end;
+ ++match_pos)
+ {
+ match_next_pos = match_pos + 1;
+ // Is this a wildcard?
+ if (match_pos->IsWildcard())
+ {
+ if (match_wildcard_pos != match_pos_end)
+ return false; // Can't have two wildcards in effect at once.
+
+ match_wildcard_pos = match_pos;
+ // Are we at the end of the MATCH token list?
+ if (match_next_pos == match_pos_end)
+ {
+ // There is nothing more to match, return if we have any matches so far...
+ return match_count > 0;
+ }
+ }
+
+ if (match_pos->type == eInvalid || match_pos->type == eError)
+ {
+ return false;
+ }
+ else
+ {
+ if (match_pos->type == eTemplateBeg)
+ {
+ ++template_scope_depth;
+ }
+ else if (match_pos->type == eTemplateEnd)
+ {
+ assert(template_scope_depth > 0);
+ --template_scope_depth;
+ }
+
+ // Do we have a wildcard going right now?
+ if (match_wildcard_pos == match_pos_end)
+ {
+ // No wildcard matching right now, just check and see if things match
+ if (*pos == *match_pos)
+ ++match_count;
+ else
+ return false;
+ }
+ else
+ {
+ // We have a wildcard match going
+
+ // For template types we need to make sure to match the template depths...
+ const size_t start_wildcard_template_scope_depth = template_scope_depth;
+ size_t curr_wildcard_template_scope_depth = template_scope_depth;
+ while (pos != pos_end)
+ {
+ if (match_wildcard_pos->type == eNameSpace && pos->type == eParamsBeg)
+ return false;
+
+ if (start_wildcard_template_scope_depth == curr_wildcard_template_scope_depth)
+ {
+ if (*pos == *match_next_pos)
+ {
+ ++match_count;
+ match_pos = match_next_pos;
+ match_wildcard_pos = match_pos_end;
+ break;
+ }
+ }
+ if (pos->type == eTemplateBeg)
+ ++curr_wildcard_template_scope_depth;
+ else if (pos->type == eTemplateEnd)
+ --curr_wildcard_template_scope_depth;
+
+
+ ++pos;
+ }
+ }
+ }
+
+ if (pos != pos_end)
+ ++pos;
+ }
+ if (match_pos != match_pos_end)
+ return false;
+
+ return match_count > 0;
+}
+
+
+//----------------------------------------------------------------------
+// Return the number of tokens in the token collection
+//----------------------------------------------------------------------
+size_t
+Mangled::TokenList::Size () const
+{
+ return m_tokens.size();
+}
+
+
+//----------------------------------------------------------------------
+// Stream out the tokens
+//----------------------------------------------------------------------
+Stream&
+lldb_private::operator << (Stream& s, const Mangled::TokenList& obj)
+{
+ obj.Dump(&s);
+ return s;
+}
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
new file mode 100644
index 00000000000..c8e7d2f2c42
--- /dev/null
+++ b/lldb/source/Core/Module.cpp
@@ -0,0 +1,515 @@
+//===-- 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/Core/Module.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Module::Module(const FileSpec& file_spec, const ArchSpec& arch, const ConstString *object_name, off_t object_offset) :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_mod_time (file_spec.GetModificationTime()),
+ m_arch (arch),
+ m_uuid (),
+ m_file (file_spec),
+ m_flags (),
+ m_object_name (),
+ m_objfile_ap (),
+ m_symfile_ap ()
+{
+ if (object_name)
+ m_object_name = *object_name;
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Module::Module((%s) '%s/%s%s%s%s')",
+ this,
+ m_arch.AsCString(),
+ m_file.GetDirectory().AsCString(""),
+ m_file.GetFilename().AsCString(""),
+ m_object_name.IsEmpty() ? "" : "(",
+ m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
+ m_object_name.IsEmpty() ? "" : ")");
+
+}
+
+Module::~Module()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Module::~Module((%s) '%s/%s%s%s%s')",
+ this,
+ m_arch.AsCString(),
+ m_file.GetDirectory().AsCString(""),
+ m_file.GetFilename().AsCString(""),
+ m_object_name.IsEmpty() ? "" : "(",
+ m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
+ m_object_name.IsEmpty() ? "" : ")");
+}
+
+
+ModuleSP
+Module::GetSP ()
+{
+ return ModuleList::GetModuleSP (this);
+}
+
+const UUID&
+Module::GetUUID()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_flags.IsClear(flagsParsedUUID))
+ {
+ ObjectFile * obj_file = GetObjectFile ();
+
+ if (obj_file != NULL)
+ {
+ obj_file->GetUUID(&m_uuid);
+ m_flags.Set(flagsParsedUUID);
+ }
+ }
+ return m_uuid;
+}
+
+void
+Module::ParseAllDebugSymbols()
+{
+ Mutex::Locker locker (m_mutex);
+ uint32_t num_comp_units = GetNumCompileUnits();
+ if (num_comp_units == 0)
+ return;
+
+ TargetSP null_target;
+ SymbolContext sc(null_target, GetSP());
+ uint32_t cu_idx;
+ SymbolVendor *symbols = GetSymbolVendor ();
+
+ for (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);
+
+ uint32_t func_idx;
+ for (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 = GetSP();
+}
+
+void
+Module::DumpSymbolContext(Stream *s)
+{
+ s->Printf(", Module{0x%8.8x}", this);
+}
+
+uint32_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 (uint32_t index)
+{
+ Mutex::Locker locker (m_mutex);
+ uint32_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;
+}
+
+//CompUnitSP
+//Module::FindCompUnit(lldb::user_id_t uid)
+//{
+// CompUnitSP cu_sp;
+// SymbolVendor *symbols = GetSymbolVendor ();
+// if (symbols)
+// cu_sp = symbols->FindCompUnit(uid);
+// 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%llx)", vm_addr);
+ ObjectFile* ofile = GetObjectFile();
+ if (ofile)
+ return so_addr.ResolveAddressUsingFileSections(vm_addr, ofile->GetSectionList());
+ 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
+ sc.Clear();
+
+ // Get the section from the section/offset address.
+ const Section *section = so_addr.GetSection();
+
+ // Make sure the section matches this module before we try and match anything
+ if (section && section->GetModule() == this)
+ {
+ // If the section offset based address resolved itself, then this
+ // is the right module.
+ sc.module_sp = GetSP();
+ 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
+ if (resolve_scope & eSymbolContextSymbol)
+ {
+ ObjectFile* ofile = GetObjectFile();
+ if (ofile)
+ {
+ Symtab *symtab = ofile->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);
+ 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%s%s:%u, check_inlines = %s, resolve_scope = 0x%8.8x)",
+ file_spec.GetDirectory().AsCString(""),
+ file_spec.GetDirectory() ? "/" : "",
+ file_spec.GetFilename().AsCString(""),
+ 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;
+}
+
+
+uint32_t
+Module::FindGlobalVariables(const ConstString &name, bool append, uint32_t max_matches, VariableList& variables)
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindGlobalVariables(name, append, max_matches, variables);
+ return 0;
+}
+uint32_t
+Module::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindGlobalVariables(regex, append, max_matches, variables);
+ return 0;
+}
+
+uint32_t
+Module::FindFunctions(const ConstString &name, bool append, SymbolContextList& sc_list)
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindFunctions(name, append, sc_list);
+ return 0;
+}
+
+uint32_t
+Module::FindFunctions(const RegularExpression& regex, bool append, SymbolContextList& sc_list)
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindFunctions(regex, append, sc_list);
+ return 0;
+}
+
+//uint32_t
+//Module::FindTypes(const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, const char *udt_name, TypeList& types)
+//{
+// Timer scoped_timer(__PRETTY_FUNCTION__);
+// SymbolVendor *symbols = GetSymbolVendor ();
+// if (symbols)
+// return symbols->FindTypes(sc, name, append, max_matches, encoding, udt_name, types);
+// return 0;
+//}
+//
+//uint32_t
+//Module::FindTypes(const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, const char *udt_name, TypeList& types)
+//{
+// Timer scoped_timer(__PRETTY_FUNCTION__);
+// SymbolVendor *symbols = GetSymbolVendor ();
+// if (symbols)
+// return symbols->FindTypes(sc, regex, append, max_matches, encoding, udt_name, types);
+// return 0;
+//
+//}
+
+SymbolVendor*
+Module::GetSymbolVendor (bool can_create)
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_flags.IsClear(flagsSearchedForSymVendor) && can_create)
+ {
+ ObjectFile *obj_file = GetObjectFile ();
+ if (obj_file != NULL)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+ m_symfile_ap.reset(SymbolVendor::FindPlugin(this));
+ m_flags.Set (flagsSearchedForSymVendor);
+ }
+ }
+ return m_symfile_ap.get();
+}
+
+const FileSpec &
+Module::GetFileSpec () const
+{
+ return m_file;
+}
+
+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;
+}
+
+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%s\n",
+ m_file.GetDirectory().AsCString(),
+ m_file.GetFilename().AsCString(),
+ 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_flags.IsClear(flagsSearchedForObjParser))
+ {
+ m_flags.Set (flagsSearchedForObjParser);
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::GetObjectFile () module = %s", GetFileSpec().GetFilename().AsCString(""));
+ m_objfile_ap.reset(ObjectFile::FindPlugin(this, &m_file, 0, m_file.GetByteSize()));
+ }
+ return m_objfile_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);
+ ObjectFile *objfile = GetObjectFile();
+ if (objfile)
+ {
+ Symtab *symtab = objfile->GetSymtab();
+ if (symtab)
+ return symtab->FindFirstSymbolWithNameAndType (name, symbol_type);
+ }
+ 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::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();
+ ObjectFile *objfile = GetObjectFile ();
+ if (objfile)
+ {
+ Symtab *symtab = objfile->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();
+ ObjectFile *objfile = GetObjectFile ();
+ if (objfile)
+ {
+ Symtab *symtab = objfile->GetSymtab();
+ if (symtab)
+ {
+ std::vector<uint32_t> symbol_indexes;
+ symtab->FindAllSymbolsMatchingRexExAndType (regex, symbol_type, symbol_indexes);
+ SymbolIndicesToSymbolContextList (symtab, symbol_indexes, sc_list);
+ }
+ }
+ return sc_list.GetSize() - initial_size;
+}
+
+const TimeValue &
+Module::GetModificationTime () const
+{
+ return m_mod_time;
+}
diff --git a/lldb/source/Core/ModuleChild.cpp b/lldb/source/Core/ModuleChild.cpp
new file mode 100644
index 00000000000..f38fb4f6c36
--- /dev/null
+++ b/lldb/source/Core/ModuleChild.cpp
@@ -0,0 +1,52 @@
+//===-- 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 (Module* module) :
+ m_module(module)
+{
+}
+
+ModuleChild::ModuleChild (const ModuleChild& rhs) :
+ m_module(rhs.m_module)
+{
+}
+
+ModuleChild::~ModuleChild()
+{
+}
+
+const ModuleChild&
+ModuleChild::operator= (const ModuleChild& rhs)
+{
+ if (this != &rhs)
+ m_module = rhs.m_module;
+ return *this;
+}
+
+Module *
+ModuleChild::GetModule ()
+{
+ return m_module;
+}
+
+Module *
+ModuleChild::GetModule () const
+{
+ return m_module;
+}
+
+void
+ModuleChild::SetModule (Module *module)
+{
+ m_module = module;
+}
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
new file mode 100644
index 00000000000..ae6e27b1dd2
--- /dev/null
+++ b/lldb/source/Core/ModuleList.cpp
@@ -0,0 +1,626 @@
+//===-- 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/Module.h"
+#include "lldb/Host/Symbols.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)
+{
+}
+
+//----------------------------------------------------------------------
+// Copy constructor
+//----------------------------------------------------------------------
+ModuleList::ModuleList(const ModuleList& rhs) :
+ m_modules(rhs.m_modules)
+{
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const ModuleList&
+ModuleList::operator= (const ModuleList& rhs)
+{
+ if (this != &rhs)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ m_modules = rhs.m_modules;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ModuleList::~ModuleList()
+{
+}
+
+void
+ModuleList::Append (ModuleSP &module_sp)
+{
+ Mutex::Locker locker(m_modules_mutex);
+ m_modules.push_back(module_sp);
+}
+
+bool
+ModuleList::AppendInNeeded (ModuleSP &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.
+ m_modules.push_back(module_sp);
+ return true;
+}
+
+bool
+ModuleList::Remove (ModuleSP &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);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+void
+ModuleList::Clear()
+{
+ Mutex::Locker locker(m_modules_mutex);
+ m_modules.clear();
+}
+
+Module*
+ModuleList::GetModulePointerAtIndex (uint32_t idx) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ if (idx < m_modules.size())
+ return m_modules[idx].get();
+ return NULL;
+}
+
+ModuleSP
+ModuleList::GetModuleAtIndex(uint32_t idx)
+{
+ Mutex::Locker locker(m_modules_mutex);
+ ModuleSP module_sp;
+ if (idx < m_modules.size())
+ module_sp = m_modules[idx];
+ return module_sp;
+}
+
+size_t
+ModuleList::FindFunctions (const ConstString &name, SymbolContextList &sc_list)
+{
+ 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)->FindFunctions (name, true, sc_list);
+ }
+ return sc_list.GetSize();
+}
+
+uint32_t
+ModuleList::FindGlobalVariables (const ConstString &name, bool append, uint32_t max_matches, VariableList& variable_list)
+{
+ size_t initial_size = variable_list.GetSize();
+ Mutex::Locker locker(m_modules_mutex);
+ collection::iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindGlobalVariables (name, append, max_matches, variable_list);
+ }
+ return variable_list.GetSize() - initial_size;
+}
+
+
+uint32_t
+ModuleList::FindGlobalVariables (const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variable_list)
+{
+ size_t initial_size = variable_list.GetSize();
+ Mutex::Locker locker(m_modules_mutex);
+ collection::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)
+{
+ Mutex::Locker locker(m_modules_mutex);
+ sc_list.Clear();
+ collection::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();
+}
+
+class ModuleMatches
+{
+public:
+ //--------------------------------------------------------------
+ /// Construct with the user ID to look for.
+ //--------------------------------------------------------------
+ ModuleMatches (const FileSpec *file_spec_ptr,
+ const ArchSpec *arch_ptr,
+ const UUID *uuid_ptr,
+ const ConstString *object_name) :
+ m_file_spec_ptr (file_spec_ptr),
+ m_arch_ptr (arch_ptr),
+ m_uuid_ptr (uuid_ptr),
+ m_object_name (object_name)
+ {
+ }
+
+ //--------------------------------------------------------------
+ /// Unary predicate function object callback.
+ //--------------------------------------------------------------
+ bool
+ operator () (const ModuleSP& module_sp) const
+ {
+ if (m_file_spec_ptr)
+ {
+ if (!FileSpec::Equal (*m_file_spec_ptr, module_sp->GetFileSpec(), m_file_spec_ptr->GetDirectory()))
+ return false;
+ }
+
+ if (m_arch_ptr)
+ {
+ if (module_sp->GetArchitecture() != *m_arch_ptr)
+ return false;
+ }
+
+ if (m_uuid_ptr)
+ {
+ if (module_sp->GetUUID() != *m_uuid_ptr)
+ return false;
+ }
+
+ if (m_object_name)
+ {
+ if (module_sp->GetObjectName() != *m_object_name)
+ return false;
+ }
+ return true;
+ }
+
+private:
+ //--------------------------------------------------------------
+ // Member variables.
+ //--------------------------------------------------------------
+ const FileSpec * m_file_spec_ptr;
+ const ArchSpec * m_arch_ptr;
+ const UUID * m_uuid_ptr;
+ const ConstString * m_object_name;
+};
+
+size_t
+ModuleList::FindModules
+(
+ const FileSpec *file_spec_ptr,
+ const ArchSpec *arch_ptr,
+ const UUID *uuid_ptr,
+ const ConstString *object_name,
+ ModuleList& matching_module_list
+) const
+{
+ size_t existing_matches = matching_module_list.GetSize();
+ ModuleMatches matcher (file_spec_ptr, arch_ptr, uuid_ptr, object_name);
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator end = m_modules.end();
+ collection::const_iterator pos;
+
+ for (pos = std::find_if (m_modules.begin(), end, matcher);
+ pos != end;
+ pos = std::find_if (++pos, end, matcher))
+ {
+ ModuleSP module_sp(*pos);
+ matching_module_list.Append(module_sp);
+ }
+ return matching_module_list.GetSize() - existing_matches;
+}
+
+ModuleSP
+ModuleList::FindModule (lldb_private::Module *module_ptr)
+{
+ 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::FindFirstModuleForFileSpec (const FileSpec &file_spec, const ConstString *object_name)
+{
+ ModuleSP module_sp;
+ ModuleMatches matcher (&file_spec, NULL, NULL, NULL);
+
+ // Scope for "locker"
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator end = m_modules.end();
+ collection::const_iterator pos = m_modules.begin();
+
+ pos = std::find_if (pos, end, matcher);
+ if (pos != end)
+ module_sp = (*pos);
+ }
+ 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);
+ }
+}
+
+
+bool
+ModuleList::ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr)
+{
+ 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)
+{
+ // The address is already section offset so it has a module
+ uint32_t resolved_flags = 0;
+ Module *module = so_addr.GetModule();
+ if (module)
+ {
+ resolved_flags = module->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)
+{
+ FileSpec file_spec(file_path);
+ 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)
+{
+ 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();
+}
+
+uint32_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 ()
+{
+ static ModuleList g_shared_module_list;
+ return g_shared_module_list;
+}
+
+const lldb::ModuleSP
+ModuleList::GetModuleSP (lldb_private::Module *module_ptr)
+{
+ lldb::ModuleSP module_sp;
+ if (module_ptr)
+ {
+ ModuleList &shared_module_list = GetSharedModuleList ();
+ module_sp = shared_module_list.FindModule (module_ptr);
+ assert (module_sp.get()); // This might fire off a few times and we need to make sure it never fires...
+ }
+ return module_sp;
+}
+
+
+Error
+ModuleList::GetSharedModule
+(
+ const FileSpec& in_file_spec,
+ const ArchSpec& arch,
+ const UUID *uuid_ptr,
+ const ConstString *object_name_ptr,
+ off_t object_offset,
+ ModuleSP &module_sp,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr
+)
+{
+ ModuleList &shared_module_list = GetSharedModuleList ();
+ char path[PATH_MAX];
+ char uuid_cstr[64];
+
+ Error error;
+
+ module_sp.reset();
+
+ if (did_create_ptr)
+ *did_create_ptr = false;
+ if (old_module_sp_ptr)
+ old_module_sp_ptr->reset();
+
+
+ // First just try and get the file where it purports to be (path in
+ // in_file_spec), then check and uuid.
+
+ if (in_file_spec)
+ {
+ // 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.
+ ModuleList matching_module_list;
+ Mutex::Locker locker(shared_module_list.m_modules_mutex);
+ if (shared_module_list.FindModules (&in_file_spec, &arch, uuid_ptr, object_name_ptr, 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 (uuid_ptr == NULL)
+ {
+ TimeValue file_spec_mod_time(in_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 (in_file_spec, arch, object_name_ptr, object_offset));
+ if (module_sp)
+ {
+ // 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.Append(module_sp);
+ return error;
+ }
+ }
+ }
+ }
+
+ // 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 (&in_file_spec, arch.IsValid() ? &arch : NULL, uuid_ptr);
+
+ // Don't look for the file if it appears to be the same one we already
+ // checked for above...
+ if (file_spec != in_file_spec)
+ {
+ if (!file_spec.Exists())
+ {
+ file_spec.GetPath(path, sizeof(path));
+ if (file_spec.Exists())
+ {
+ if (uuid_ptr && uuid_ptr->IsValid())
+ uuid_ptr->GetAsCString(uuid_cstr, sizeof (uuid_cstr));
+ else
+ uuid_cstr[0] = '\0';
+
+
+ if (arch.IsValid())
+ {
+ if (uuid_cstr[0])
+ error.SetErrorStringWithFormat("'%s' does not contain the %s architecture and UUID %s.\n", path, arch.AsCString(), uuid_cstr[0]);
+ else
+ error.SetErrorStringWithFormat("'%s' does not contain the %s architecture.\n", path, arch.AsCString());
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' does not exist.\n", path);
+ }
+ 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.
+ Mutex::Locker locker(shared_module_list.m_modules_mutex);
+ ModuleList matching_module_list;
+ if (shared_module_list.FindModules (&file_spec, &arch, uuid_ptr, object_name_ptr, 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 (uuid_ptr == 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 (file_spec, arch, object_name_ptr, object_offset));
+ if (module_sp)
+ {
+ if (did_create_ptr)
+ *did_create_ptr = true;
+
+ shared_module_list.Append(module_sp);
+ }
+ else
+ {
+ file_spec.GetPath(path, sizeof(path));
+
+ if (file_spec)
+ {
+ if (arch.IsValid())
+ error.SetErrorStringWithFormat("Unable to open %s architecture in '%s'.\n", arch.AsCString(), path);
+ else
+ error.SetErrorStringWithFormat("Unable to open '%s'.\n", path);
+ }
+ else
+ {
+ if (uuid_ptr && uuid_ptr->IsValid())
+ uuid_ptr->GetAsCString(uuid_cstr, sizeof (uuid_cstr));
+ else
+ uuid_cstr[0] = '\0';
+
+ if (uuid_cstr[0])
+ error.SetErrorStringWithFormat("Cannot locate a module for UUID '%s'.\n", uuid_cstr[0]);
+ else
+ error.SetErrorStringWithFormat("Cannot locate a module.\n", path, arch.AsCString());
+ }
+ }
+ }
+ }
+
+ return error;
+}
+
diff --git a/lldb/source/Core/Options.cpp b/lldb/source/Core/Options.cpp
new file mode 100644
index 00000000000..35a9fa40e1b
--- /dev/null
+++ b/lldb/source/Core/Options.cpp
@@ -0,0 +1,700 @@
+//===-- 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/Core/Options.h"
+
+// C Includes
+// C++ Includes
+#include <bitset>
+
+// 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 () :
+ m_getopt_table ()
+{
+}
+
+Options::~Options ()
+{
+}
+
+
+void
+Options::ResetOptionValues ()
+{
+ m_seen_options.clear();
+}
+
+void
+Options::OptionSeen (int option_idx)
+{
+ m_seen_options.insert ((char) 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 = m_required_options.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 (m_required_options[i], m_seen_options))
+ {
+ // Construct the set difference: remaining_options = {m_seen_options} - {m_required_options[i]}
+ OptionSet remaining_options;
+ OptionsSetDiff (m_seen_options, m_required_options[i], remaining_options);
+ // Check to see if remaining_options is a subset of m_optional_options[i]
+ if (IsASubset (remaining_options, m_optional_options[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;
+}
+
+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 lldb::OptionDefinition *full_options_table = GetDefinitions();
+ uint32_t usage_level = 0;
+ m_required_options.resize(1);
+ m_optional_options.resize(1);
+
+ for (int i = 0; i < num_options; ++i)
+ {
+ // NOTE: Assumption: The full options table is ordered with usage level growing monotonically.
+ assert (full_options_table[i].usage_level >= usage_level);
+
+ if (full_options_table[i].usage_level > usage_level)
+ {
+ // start a new level
+ usage_level = full_options_table[i].usage_level;
+ m_required_options.resize(m_required_options.size()+1);
+ m_optional_options.resize(m_optional_options.size()+1);
+ }
+ else
+ {
+ assert (m_required_options.empty() == false);
+ assert (m_optional_options.empty() == false);
+ }
+
+ if (full_options_table[i].required)
+ m_required_options.back().insert(full_options_table[i].short_option);
+ else
+ m_optional_options.back().insert(full_options_table[i].short_option);
+ }
+}
+
+uint32_t
+Options::NumCommandOptions ()
+{
+ const lldb::OptionDefinition *full_options_table = GetDefinitions ();
+ int i = 0;
+
+ if (full_options_table != NULL)
+ {
+ while (full_options_table[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;
+ uint32_t j;
+ const lldb::OptionDefinition *full_options_table = GetDefinitions();
+
+ std::bitset<256> option_seen;
+
+ m_getopt_table.resize(num_options + 1);
+ for (i = 0, j = 0; i < num_options; ++i)
+ {
+ char short_opt = full_options_table[i].short_option;
+
+ if (option_seen.test(short_opt) == false)
+ {
+ m_getopt_table[j].name = full_options_table[i].long_option;
+ m_getopt_table[j].has_arg = full_options_table[i].option_has_arg;
+ m_getopt_table[j].flag = NULL;
+ m_getopt_table[j].val = full_options_table[i].short_option;
+ option_seen.set(short_opt);
+ ++j;
+ }
+ }
+
+ //getopt_long requires a NULL final entry in the table:
+
+ m_getopt_table[j].name = NULL;
+ m_getopt_table[j].has_arg = 0;
+ m_getopt_table[j].flag = NULL;
+ m_getopt_table[j].val = 0;
+ }
+
+ return m_getopt_table.data();
+}
+
+
+// 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();
+ }
+}
+
+void
+Options::GenerateOptionUsage
+(
+ Stream &strm,
+ CommandObject *cmd,
+ const char *program_name)
+{
+ uint32_t screen_width = 80;
+ const lldb::OptionDefinition *full_options_table = GetDefinitions();
+ const uint32_t save_indent_level = strm.GetIndentLevel();
+ const char *name;
+
+ if (cmd)
+ name = cmd->GetCommandName();
+ else
+ name = program_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.
+
+ uint32_t usage_level = 0;
+ const uint32_t num_options = NumCommandOptions();
+ uint32_t i;
+ for (i = 0; i < num_options; ++i)
+ {
+ if (i==0 || full_options_table[i].usage_level > usage_level)
+ {
+ // start a new level
+ usage_level = full_options_table[i].usage_level;
+ if (usage_level > 0)
+ {
+ strm.Printf ("\n");
+ }
+ strm.Indent (name);
+ }
+
+ // Add current option to the end of out_stream.
+
+ if (full_options_table[i].required)
+ {
+ if (full_options_table[i].option_has_arg == required_argument)
+ {
+ strm.Printf (" -%c %s",
+ full_options_table[i].short_option,
+ full_options_table[i].argument_name);
+ }
+ else if (full_options_table[i].option_has_arg == optional_argument)
+ {
+ strm.Printf (" -%c [%s]",
+ full_options_table[i].short_option,
+ full_options_table[i].argument_name);
+ }
+ else
+ strm.Printf (" -%c", full_options_table[i].short_option);
+ }
+ else
+ {
+ if (full_options_table[i].option_has_arg == required_argument)
+ strm.Printf (" [-%c %s]", full_options_table[i].short_option,
+ full_options_table[i].argument_name);
+ else if (full_options_table[i].option_has_arg == optional_argument)
+ strm.Printf (" [-%c [%s]]", full_options_table[i].short_option,
+ full_options_table[i].argument_name);
+ else
+ strm.Printf (" [-%c]", full_options_table[i].short_option);
+ }
+ }
+
+ 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.
+
+ OptionSet options_seen;
+ OptionSet::iterator pos;
+ strm.IndentMore (5);
+
+ int first_option_printed = 1;
+ for (i = 0; i < num_options; ++i)
+ {
+ // Only print out this option if we haven't already seen it.
+ pos = options_seen.find (full_options_table[i].short_option);
+ if (pos == options_seen.end())
+ {
+ // Put a newline separation between arguments
+ if (first_option_printed)
+ first_option_printed = 0;
+ else
+ strm.EOL();
+
+ options_seen.insert (full_options_table[i].short_option);
+ strm.Indent ();
+ strm.Printf ("-%c ", full_options_table[i].short_option);
+ if (full_options_table[i].argument_name != NULL)
+ strm.PutCString(full_options_table[i].argument_name);
+ strm.EOL();
+ strm.Indent ();
+ strm.Printf ("--%s ", full_options_table[i].long_option);
+ if (full_options_table[i].argument_name != NULL)
+ strm.PutCString(full_options_table[i].argument_name);
+ strm.EOL();
+
+ strm.IndentMore (5);
+
+ if (full_options_table[i].usage_text)
+ OutputFormattedUsageText (strm,
+ full_options_table[i].usage_text,
+ screen_width);
+ if (full_options_table[i].enum_values != NULL)
+ {
+ strm.Indent ();
+ strm.Printf("Values: ");
+ for (int j = 0; full_options_table[i].enum_values[j].string_value != NULL; j++)
+ {
+ if (j == 0)
+ strm.Printf("%s", full_options_table[i].enum_values[j].string_value);
+ else
+ strm.Printf(" | %s", full_options_table[i].enum_values[j].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 = m_required_options.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 (m_required_options[i], m_optional_options[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,
+ lldb_private::CommandInterpreter *interpreter,
+ lldb_private::StringList &matches
+)
+{
+ // 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 (int 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 != -1)
+ {
+ // We recognized it, if it an incomplete long option, complete it anyway (getopt_long 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 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 i = 0 ; opt_defs[i].short_option != 0 ; i++)
+ {
+ if (strstr(opt_defs[i].long_option, cur_opt_str + 2) == opt_defs[i].long_option)
+ {
+ std::string full_name ("--");
+ full_name.append (opt_defs[i].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 (int j = 0; j < matches.GetSize(); j++)
+ {
+ if (matches.GetStringAtIndex(j) == 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,
+ interpreter,
+ 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,
+ lldb_private::CommandInterpreter *interpreter,
+ lldb_private::StringList &matches
+)
+{
+ const OptionDefinition *opt_defs = GetDefinitions();
+ std::auto_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].completionType;
+ if (completion_mask & CommandCompletions::eSourceFileCompletion
+ || completion_mask & CommandCompletions::eSymbolCompletion)
+ {
+ for (int 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);
+ lldb::TargetSP target_sp = interpreter->Context()->GetTarget()->GetSP();
+ // Search filters require a target...
+ if (target_sp != NULL)
+ filter_ap.reset (new SearchFilterByModule (target_sp, module_spec));
+ }
+ break;
+ }
+ }
+ }
+
+ return CommandCompletions::InvokeCommonCompletionCallbacks (completion_mask,
+ input.GetArgumentAtIndex (opt_arg_pos),
+ match_start_point,
+ max_return_elements,
+ interpreter,
+ filter_ap.get(),
+ matches);
+
+}
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
new file mode 100644
index 00000000000..3723e7cf89a
--- /dev/null
+++ b/lldb/source/Core/PluginManager.cpp
@@ -0,0 +1,1133 @@
+//===-- 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/Core/PluginManager.h"
+
+#include <string>
+#include <vector>
+
+using namespace lldb_private;
+
+typedef enum PluginAction
+{
+ ePluginRegisterInstance,
+ ePluginUnregisterInstance,
+ ePluginGetInstanceAtIndex
+};
+
+
+#pragma mark ABI
+
+
+typedef struct ABIInstance
+{
+ ABIInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ ABICreateInstance create_callback;
+};
+
+typedef std::vector<ABIInstance> ABIInstances;
+
+static bool
+AccessABIInstances (PluginAction action, ABIInstance &instance, uint32_t index)
+{
+ static ABIInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ ABIInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+ (
+ const char *name,
+ const char *description,
+ ABICreateInstance create_callback
+ )
+{
+ if (create_callback)
+ {
+ ABIInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessABIInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ABICreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ ABIInstance instance;
+ instance.create_callback = create_callback;
+ return AccessABIInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+ABICreateInstance
+PluginManager::GetABICreateCallbackAtIndex (uint32_t idx)
+{
+ ABIInstance instance;
+ if (AccessABIInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+
+ABICreateInstance
+PluginManager::GetABICreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ ABIInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessABIInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+#pragma mark Disassembler
+
+
+typedef struct DisassemblerInstance
+{
+ DisassemblerInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ DisassemblerCreateInstance create_callback;
+};
+
+typedef std::vector<DisassemblerInstance> DisassemblerInstances;
+
+static bool
+AccessDisassemblerInstances (PluginAction action, DisassemblerInstance &instance, uint32_t index)
+{
+ static DisassemblerInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ DisassemblerInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ DisassemblerCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ DisassemblerInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessDisassemblerInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (DisassemblerCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ DisassemblerInstance instance;
+ instance.create_callback = create_callback;
+ return AccessDisassemblerInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+DisassemblerCreateInstance
+PluginManager::GetDisassemblerCreateCallbackAtIndex (uint32_t idx)
+{
+ DisassemblerInstance instance;
+ if (AccessDisassemblerInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+
+DisassemblerCreateInstance
+PluginManager::GetDisassemblerCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ DisassemblerInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessDisassemblerInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+#pragma mark DynamicLoader
+
+
+typedef struct DynamicLoaderInstance
+{
+ DynamicLoaderInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ DynamicLoaderCreateInstance create_callback;
+};
+
+typedef std::vector<DynamicLoaderInstance> DynamicLoaderInstances;
+
+static bool
+AccessDynamicLoaderInstances (PluginAction action, DynamicLoaderInstance &instance, uint32_t index)
+{
+ static DynamicLoaderInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ DynamicLoaderInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ DynamicLoaderCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ DynamicLoaderInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessDynamicLoaderInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (DynamicLoaderCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ DynamicLoaderInstance instance;
+ instance.create_callback = create_callback;
+ return AccessDynamicLoaderInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+DynamicLoaderCreateInstance
+PluginManager::GetDynamicLoaderCreateCallbackAtIndex (uint32_t idx)
+{
+ DynamicLoaderInstance instance;
+ if (AccessDynamicLoaderInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+
+DynamicLoaderCreateInstance
+PluginManager::GetDynamicLoaderCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ DynamicLoaderInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessDynamicLoaderInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+
+#pragma mark ObjectFile
+
+typedef struct ObjectFileInstance
+{
+ ObjectFileInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ ObjectFileCreateInstance create_callback;
+};
+
+typedef std::vector<ObjectFileInstance> ObjectFileInstances;
+
+static bool
+AccessObjectFileInstances (PluginAction action, ObjectFileInstance &instance, uint32_t index)
+{
+ static ObjectFileInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ ObjectFileInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ ObjectFileCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ ObjectFileInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessObjectFileInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ObjectFileCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ ObjectFileInstance instance;
+ instance.create_callback = create_callback;
+ return AccessObjectFileInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+ObjectFileCreateInstance
+PluginManager::GetObjectFileCreateCallbackAtIndex (uint32_t idx)
+{
+ ObjectFileInstance instance;
+ if (AccessObjectFileInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+ObjectFileCreateInstance
+PluginManager::GetObjectFileCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ ObjectFileInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessObjectFileInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+#pragma mark ObjectContainer
+
+typedef struct ObjectContainerInstance
+{
+ ObjectContainerInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ ObjectContainerCreateInstance create_callback;
+};
+
+typedef std::vector<ObjectContainerInstance> ObjectContainerInstances;
+
+static bool
+AccessObjectContainerInstances (PluginAction action, ObjectContainerInstance &instance, uint32_t index)
+{
+ static ObjectContainerInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ ObjectContainerInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ ObjectContainerCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ ObjectContainerInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessObjectContainerInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ObjectContainerCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ ObjectContainerInstance instance;
+ instance.create_callback = create_callback;
+ return AccessObjectContainerInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+ObjectContainerCreateInstance
+PluginManager::GetObjectContainerCreateCallbackAtIndex (uint32_t idx)
+{
+ ObjectContainerInstance instance;
+ if (AccessObjectContainerInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+ObjectContainerCreateInstance
+PluginManager::GetObjectContainerCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ ObjectContainerInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessObjectContainerInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark LogChannel
+
+typedef struct LogChannelInstance
+{
+ LogChannelInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ LogChannelCreateInstance create_callback;
+};
+
+typedef std::vector<LogChannelInstance> LogChannelInstances;
+
+static bool
+AccessLogChannelInstances (PluginAction action, LogChannelInstance &instance, uint32_t index)
+{
+ static LogChannelInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ LogChannelInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ LogChannelCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ LogChannelInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessLogChannelInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (LogChannelCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ LogChannelInstance instance;
+ instance.create_callback = create_callback;
+ return AccessLogChannelInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+const char *
+PluginManager::GetLogChannelCreateNameAtIndex (uint32_t idx)
+{
+ LogChannelInstance instance;
+ if (AccessLogChannelInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.name.c_str();
+ return NULL;
+}
+
+
+LogChannelCreateInstance
+PluginManager::GetLogChannelCreateCallbackAtIndex (uint32_t idx)
+{
+ LogChannelInstance instance;
+ if (AccessLogChannelInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+
+LogChannelCreateInstance
+PluginManager::GetLogChannelCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ LogChannelInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessLogChannelInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark Process
+
+typedef struct ProcessInstance
+{
+ ProcessInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ ProcessCreateInstance create_callback;
+};
+
+typedef std::vector<ProcessInstance> ProcessInstances;
+
+static bool
+AccessProcessInstances (PluginAction action, ProcessInstance &instance, uint32_t index)
+{
+ static ProcessInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ ProcessInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ ProcessCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ ProcessInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessProcessInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ProcessCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ ProcessInstance instance;
+ instance.create_callback = create_callback;
+ return AccessProcessInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+ProcessCreateInstance
+PluginManager::GetProcessCreateCallbackAtIndex (uint32_t idx)
+{
+ ProcessInstance instance;
+ if (AccessProcessInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+
+ProcessCreateInstance
+PluginManager::GetProcessCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ ProcessInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessProcessInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark SymbolFile
+
+typedef struct SymbolFileInstance
+{
+ SymbolFileInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ SymbolFileCreateInstance create_callback;
+};
+
+typedef std::vector<SymbolFileInstance> SymbolFileInstances;
+
+static bool
+AccessSymbolFileInstances (PluginAction action, SymbolFileInstance &instance, uint32_t index)
+{
+ static SymbolFileInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ SymbolFileInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ SymbolFileCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ SymbolFileInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessSymbolFileInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (SymbolFileCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ SymbolFileInstance instance;
+ instance.create_callback = create_callback;
+ return AccessSymbolFileInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+SymbolFileCreateInstance
+PluginManager::GetSymbolFileCreateCallbackAtIndex (uint32_t idx)
+{
+ SymbolFileInstance instance;
+ if (AccessSymbolFileInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+SymbolFileCreateInstance
+PluginManager::GetSymbolFileCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ SymbolFileInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessSymbolFileInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+#pragma mark SymbolVendor
+
+typedef struct SymbolVendorInstance
+{
+ SymbolVendorInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ std::string name;
+ std::string description;
+ SymbolVendorCreateInstance create_callback;
+};
+
+typedef std::vector<SymbolVendorInstance> SymbolVendorInstances;
+
+static bool
+AccessSymbolVendorInstances (PluginAction action, SymbolVendorInstance &instance, uint32_t index)
+{
+ static SymbolVendorInstances g_plugin_instances;
+
+ switch (action)
+ {
+ case ePluginRegisterInstance:
+ if (instance.create_callback)
+ {
+ g_plugin_instances.push_back (instance);
+ return true;
+ }
+ break;
+
+ case ePluginUnregisterInstance:
+ if (instance.create_callback)
+ {
+ SymbolVendorInstances::iterator pos, end = g_plugin_instances.end();
+ for (pos = g_plugin_instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == instance.create_callback)
+ {
+ g_plugin_instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case ePluginGetInstanceAtIndex:
+ if (index < g_plugin_instances.size())
+ {
+ instance = g_plugin_instances[index];
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const char *name,
+ const char *description,
+ SymbolVendorCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ SymbolVendorInstance instance;
+ assert (name && name[0]);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ return AccessSymbolVendorInstances (ePluginRegisterInstance, instance, 0);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (SymbolVendorCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ SymbolVendorInstance instance;
+ instance.create_callback = create_callback;
+ return AccessSymbolVendorInstances (ePluginUnregisterInstance, instance, 0);
+ }
+ return false;
+}
+
+SymbolVendorCreateInstance
+PluginManager::GetSymbolVendorCreateCallbackAtIndex (uint32_t idx)
+{
+ SymbolVendorInstance instance;
+ if (AccessSymbolVendorInstances (ePluginGetInstanceAtIndex, instance, idx))
+ return instance.create_callback;
+ return false;
+}
+
+SymbolVendorCreateInstance
+PluginManager::GetSymbolVendorCreateCallbackForPluginName (const char *name)
+{
+ if (name && name[0])
+ {
+ SymbolVendorInstance instance;
+ std::string ss_name(name);
+ for (uint32_t idx = 0; AccessSymbolVendorInstances (ePluginGetInstanceAtIndex, instance, idx); ++idx)
+ {
+ if (instance.name == ss_name)
+ return instance.create_callback;
+ }
+ }
+ return NULL;
+}
+
+
diff --git a/lldb/source/Core/RegularExpression.cpp b/lldb/source/Core/RegularExpression.cpp
new file mode 100644
index 00000000000..aca1671c181
--- /dev/null
+++ b/lldb/source/Core/RegularExpression.cpp
@@ -0,0 +1,154 @@
+//===-- 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"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+RegularExpression::RegularExpression() :
+ m_re(),
+ m_comp_err (1),
+ m_preg(),
+ m_matches()
+{
+ 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()
+{
+ memset(&m_preg,0,sizeof(m_preg));
+ Compile(re, flags);
+}
+
+//----------------------------------------------------------------------
+// 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, int flags)
+{
+ Free();
+ 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, size_t num_matches, int execute_flags) const
+{
+ int match_result = 1;
+ if (m_comp_err == 0)
+ {
+ if (num_matches > 0)
+ m_matches.resize(num_matches + 1);
+ else
+ m_matches.clear();
+
+ match_result = ::regexec (&m_preg,
+ s,
+ m_matches.size(),
+ const_cast<regmatch_t *>(m_matches.data()),
+ execute_flags);
+ }
+ return match_result == 0;
+}
+
+bool
+RegularExpression::GetMatchAtIndex (const char* s, uint32_t idx, std::string& match_str) const
+{
+ if (idx <= m_preg.re_nsub && idx < m_matches.size())
+ {
+ match_str.assign (s + m_matches[idx].rm_so,
+ m_matches[idx].rm_eo - m_matches[idx].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
+{
+ 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;
+ }
+}
diff --git a/lldb/source/Core/Scalar.cpp b/lldb/source/Core/Scalar.cpp
new file mode 100644
index 00000000000..56590b8d69e
--- /dev/null
+++ b/lldb/source/Core/Scalar.cpp
@@ -0,0 +1,2084 @@
+//===-- 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 "lldb/Core/Args.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/DataExtractor.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 (eByteOrderHost == 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, eByteOrderHost);
+ }
+ else if (eByteOrderHost == 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, eByteOrderHost);
+ }
+ }
+ else
+ {
+ // We want all of the data
+ data.SetData((uint8_t*)&m_data, byte_size, eByteOrderHost);
+ }
+ return true;
+ }
+ data.Clear();
+ return false;
+}
+
+size_t
+Scalar::GetByteSize() const
+{
+ switch (m_type)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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:
+ default:
+ 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)
+ {
+ default:
+ break;
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default: break;
+ 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(int))
+ return e_sint;
+ if (byte_size <= sizeof(long))
+ return e_slong;
+ if (byte_size <= sizeof(long long))
+ return e_slonglong;
+ return e_void;
+}
+
+Scalar::Type
+Scalar::GetValueTypeForUnsignedIntegerWithByteSize (size_t byte_size)
+{
+ if (byte_size <= sizeof(unsigned int))
+ return e_uint;
+ if (byte_size <= sizeof(unsigned long))
+ return e_ulong;
+ if (byte_size <= sizeof(unsigned long long))
+ return e_ulonglong;
+ return e_void;
+}
+
+Scalar::Type
+Scalar::GetValueTypeForFloatWithByteSize (size_t byte_size)
+{
+ if (byte_size == sizeof(float))
+ return e_float;
+ if (byte_size == sizeof(double))
+ return e_double;
+ if (byte_size == sizeof(long double))
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.slong; success = true; break;
+ case e_uint: m_data.uint = 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.ulong; success = true; break;
+ case e_uint: m_data.uint = 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.slonglong; success = true; break;
+ case e_uint: m_data.uint = 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.ulonglong; success = true; break;
+ case e_uint: m_data.uint = 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.flt; success = true; break;
+ case e_uint: m_data.uint = m_data.flt; success = true; break;
+ case e_slong: m_data.slong = m_data.flt; success = true; break;
+ case e_ulong: m_data.ulong = m_data.flt; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.flt; success = true; break;
+ case e_ulonglong: m_data.ulonglong = 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.dbl; success = true; break;
+ case e_uint: m_data.uint = m_data.dbl; success = true; break;
+ case e_slong: m_data.slong = m_data.dbl; success = true; break;
+ case e_ulong: m_data.ulong = m_data.dbl; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.dbl; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.dbl; success = true; break;
+ case e_float: m_data.flt = 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)
+ {
+ default:
+ case e_void:
+ case e_sint: m_data.sint = m_data.ldbl; success = true; break;
+ case e_uint: m_data.uint = m_data.ldbl; success = true; break;
+ case e_slong: m_data.slong = m_data.ldbl; success = true; break;
+ case e_ulong: m_data.ulong = m_data.ldbl; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.ldbl; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.ldbl; success = true; break;
+ case e_float: m_data.flt = m_data.ldbl; success = true; break;
+ case e_double: m_data.dbl = m_data.ldbl; success = true; break;
+ case e_long_double: success = true; break;
+ }
+ break;
+ }
+
+ if (success)
+ m_type = type;
+ return success;
+}
+
+int
+Scalar::SInt(int fail_value) const
+{
+ switch (m_type)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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(int))
+ return m_data.uint;
+ else if (sizeof(m_data.flt) == sizeof(unsigned long))
+ return m_data.ulong;
+ else if (sizeof(m_data.flt) == sizeof(unsigned long long))
+ return m_data.ulonglong;
+ break;
+
+ case e_double:
+ if (sizeof(m_data.dbl) == sizeof(int))
+ return m_data.uint;
+ else if (sizeof(m_data.dbl) == sizeof(unsigned long))
+ return m_data.ulong;
+ else if (sizeof(m_data.dbl) == sizeof(unsigned long long))
+ return m_data.ulonglong;
+ break;
+
+ case e_long_double:
+ if (sizeof(m_data.ldbl) == sizeof(int))
+ return m_data.uint;
+ else if (sizeof(m_data.ldbl) == sizeof(unsigned long))
+ return m_data.ulong;
+ else if (sizeof(m_data.ldbl) == sizeof(unsigned long long))
+ return m_data.ulonglong;
+ break;
+ }
+ return fail_value;
+}
+
+
+
+long long
+Scalar::SLongLong(long long fail_value) const
+{
+ switch (m_type)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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;
+
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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)
+ {
+ default:
+ 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;
+
+ default:
+ 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;
+
+ default:
+ 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;
+
+ default:
+ 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;
+
+ default:
+ 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;
+}
+
+// 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, uint32_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)
+ {
+ default:
+ 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.\n", value_str);
+ else if (!UIntValueIsValidForSize (uval64, byte_size))
+ error.SetErrorStringWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, byte_size);
+ else
+ {
+ m_type = Scalar::GetValueTypeForUnsignedIntegerWithByteSize (byte_size);
+ switch (m_type)
+ {
+ case e_uint: m_data.uint = uval64; break;
+ case e_ulong: m_data.ulong = uval64; break;
+ case e_ulonglong: m_data.ulonglong = uval64; break;
+ default:
+ error.SetErrorStringWithFormat ("Unsupported unsigned integer byte size: %u.\n", byte_size);
+ break;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Unsupported unsigned integer byte size: %u.\n", 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.\n", value_str);
+ else if (!SIntValueIsValidForSize (sval64, byte_size))
+ error.SetErrorStringWithFormat ("Value 0x%llx is too large to fit in a %u byte signed integer value.\n", sval64, byte_size);
+ else
+ {
+ m_type = Scalar::GetValueTypeForSignedIntegerWithByteSize (byte_size);
+ switch (m_type)
+ {
+ case e_sint: m_data.sint = sval64; break;
+ case e_slong: m_data.slong = sval64; break;
+ case e_slonglong: m_data.slonglong = sval64; break;
+ default:
+ error.SetErrorStringWithFormat ("Unsupported signed integer byte size: %u.\n", byte_size);
+ break;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Unsupported signed integer byte size: %u.\n", 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.\n", 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.\n", 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.\n", value_str);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Unsupported float byte size: %u.\n", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingVector:
+ error.SetErrorString ("Vector encoding unsupported.");
+ break;
+ }
+ if (error.Fail())
+ m_type = e_void;
+
+ return error;
+}
+
+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))
+ {
+ default:
+ 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))
+ {
+ default:
+ 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))
+ {
+ default:
+ 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))
+ {
+ default:
+ 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))
+ {
+ default:
+ 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))
+ {
+ default:
+ 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/lldb/source/Core/SearchFilter.cpp b/lldb/source/Core/SearchFilter.cpp
new file mode 100644
index 00000000000..4c54a912801
--- /dev/null
+++ b/lldb/source/Core/SearchFilter.cpp
@@ -0,0 +1,435 @@
+//===-- 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/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(lldb::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::SymbolContextPasses
+(
+ const SymbolContext &context,
+ lldb::SymbolContextItem scope
+)
+{
+ return true;
+}
+
+bool
+SearchFilter::AddressPasses (Address &address)
+{
+ return true;
+}
+
+bool
+SearchFilter::CompUnitPasses (FileSpec &fileSpec)
+{
+ return true;
+}
+
+bool
+SearchFilter::CompUnitPasses (CompileUnit &compUnit)
+{
+ return true;
+}
+
+void
+SearchFilter::GetDescription (Stream *s)
+{
+ s->PutCString("No Filter");
+}
+
+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 == NULL)
+ 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 == NULL)
+ return;
+ empty_sc.target_sp = m_target_sp;
+
+ if (searcher.GetDepth() == Searcher::eDepthTarget)
+ searcher.SearchCallback (*this, empty_sc, NULL, false);
+ else
+ {
+ size_t numModules = modules.GetSize();
+
+ for (int i = 0; i < numModules; i++)
+ {
+ ModuleSP module_sp(modules.GetModuleAtIndex(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)
+{
+ Searcher::CallbackReturn shouldContinue;
+
+ if (searcher.GetDepth () >= Searcher::eDepthModule)
+ {
+ if (!context.module_sp)
+ {
+ size_t n_modules = m_target_sp->GetImages().GetSize();
+ for (int i = 0; i < n_modules; i++)
+ {
+ // If this is the last level supplied, then call the callback directly,
+ // otherwise descend.
+ ModuleSP module_sp(m_target_sp->GetImages().GetModuleAtIndex(i));
+ if (!ModulePasses (module_sp))
+ continue;
+
+ if (searcher.GetDepth () == Searcher::eDepthModule)
+ {
+ SymbolContext matchingContext(m_target_sp, module_sp);
+
+ shouldContinue = searcher.SearchCallback (*this, matchingContext, NULL, false);
+ if (shouldContinue == Searcher::eCallbackReturnStop
+ || shouldContinue == Searcher::eCallbackReturnPop)
+ return shouldContinue;
+ }
+ else
+ {
+ shouldContinue = DoCUIteration(module_sp, context, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return shouldContinue;
+ else if (shouldContinue == Searcher::eCallbackReturnPop)
+ continue;
+ }
+ }
+ }
+ else
+ {
+ if (searcher.GetDepth () == Searcher::eDepthModule)
+ {
+ SymbolContext matchingContext(context.module_sp.get());
+
+ shouldContinue = searcher.SearchCallback (*this, matchingContext, NULL, false);
+ }
+ else
+ {
+ return DoCUIteration(context.module_sp, context, searcher);
+ }
+ }
+
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::CallbackReturn
+SearchFilter::DoCUIteration (const ModuleSP &module_sp, const SymbolContext &context, Searcher &searcher)
+{
+ Searcher::CallbackReturn shouldContinue;
+ if (context.comp_unit == NULL)
+ {
+ uint32_t num_comp_units = module_sp->GetNumCompileUnits();
+ for (uint32_t i = 0; i < num_comp_units; i++)
+ {
+ CompUnitSP cu_sp (module_sp->GetCompileUnitAtIndex (i));
+ 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;
+}
+
+//----------------------------------------------------------------------
+// SearchFilterByModule:
+// Selects a shared library matching a given file spec
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// SearchFilterByModule constructors
+//----------------------------------------------------------------------
+
+SearchFilterByModule::SearchFilterByModule (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::Compare (module_sp->GetFileSpec(), m_module_spec, false) == 0)
+ return true;
+ else
+ return false;
+}
+
+bool
+SearchFilterByModule::ModulePasses (const FileSpec &spec)
+{
+ if (FileSpec::Compare(spec, m_module_spec, false) == 0)
+ return true;
+ else
+ return false;
+}
+
+bool
+SearchFilterByModule::SymbolContextPasses
+(
+ const SymbolContext &context,
+ lldb::SymbolContextItem scope
+ )
+{
+ if (!(scope & eSymbolContextModule))
+ return false;
+
+ if (context.module_sp && FileSpec::Compare (context.module_sp->GetFileSpec(), m_module_spec, false) == 0)
+ return true;
+ else
+ return false;
+}
+
+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.
+
+ ModuleList matching_modules;
+ // const size_t num_matching_modules = m_target_sp->GetImages().FindModules(&m_module_spec, NULL, NULL, NULL, matching_modules);
+ for (int i = 0; i < m_target_sp->GetImages().GetSize (); i++)
+ {
+ Module* module = m_target_sp->GetImages().GetModulePointerAtIndex(i);
+ if (FileSpec::Compare (m_module_spec, module->GetFileSpec(), false) == 0)
+ {
+ SymbolContext matchingContext(m_target_sp, module->GetSP());
+ Searcher::CallbackReturn shouldContinue;
+
+ shouldContinue = DoModuleIteration(matchingContext, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return;
+ }
+ }
+}
+
+void
+SearchFilterByModule::GetDescription (Stream *s)
+{
+ s->PutCString("In 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>"));
+ }
+}
+
+void
+SearchFilterByModule::Dump (Stream *s) const
+{
+
+}
diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp
new file mode 100644
index 00000000000..57c519918f2
--- /dev/null
+++ b/lldb/source/Core/Section.cpp
@@ -0,0 +1,791 @@
+//===-- 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/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Section::Section
+(
+ Section *parent,
+ Module* module,
+ user_id_t sect_id,
+ const ConstString &name,
+ SectionType sect_type,
+ addr_t file_addr,
+ addr_t byte_size,
+ uint64_t file_offset,
+ uint64_t file_size,
+ uint32_t flags
+) :
+ ModuleChild (module),
+ UserID (sect_id),
+ Flags (flags),
+ m_parent (parent),
+ m_name (name),
+ m_type (sect_type),
+ 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_linked_section(NULL),
+ m_linked_offset (0)
+{
+}
+
+//Section::Section
+//(
+// Section *parent,
+// Module* module,
+// user_id_t sect_id,
+// const ConstString &name,
+// const AddressRange *file_vm_range,
+// uint64_t file_offset,
+// uint64_t file_size,
+// uint32_t flags
+//) :
+// ModuleChild (module),
+// UserID (sect_id),
+// Flags (flags),
+// m_parent (parent),
+// m_name (name),
+// m_range (),
+// m_file_offset (file_offset),
+// m_file_size (file_size),
+// m_children (),
+// m_fake (false)
+//{
+// if (file_vm_range)
+// m_range = *file_vm_range;
+//}
+
+Section::~Section()
+{
+}
+
+
+// Get a valid shared pointer to this section object
+SectionSP
+Section::GetSharedPointer() const
+{
+ SectionSP this_sp;
+ if (m_parent)
+ this_sp = m_parent->GetChildren().GetSharedPointer (this, false);
+ else
+ {
+ ObjectFile *objfile = m_module->GetObjectFile();
+ if (objfile)
+ {
+ SectionList *section_list = objfile->GetSectionList();
+ if (section_list)
+ this_sp = section_list->GetSharedPointer (this, false);
+ }
+ }
+ return this_sp;
+}
+
+
+
+ConstString&
+Section::GetName()
+{
+ if (m_linked_section)
+ return const_cast<Section *>(m_linked_section)->GetName();
+ return m_name;
+}
+
+const ConstString&
+Section::GetName() const
+{
+ if (m_linked_section)
+ return m_linked_section->GetName();
+ return m_name;
+}
+
+SectionList&
+Section::GetChildren()
+{
+ return m_children;
+}
+
+const SectionList&
+Section::GetChildren() const
+{
+ return m_children;
+}
+
+addr_t
+Section::GetFileAddress () const
+{
+ if (m_parent)
+ {
+ // 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 m_parent->GetFileAddress() + m_file_addr;
+ }
+ // This section has no parent, so m_file_addr is the file base address
+ return m_file_addr;
+}
+
+addr_t
+Section::GetLinkedFileAddress () const
+{
+ if (m_linked_section)
+ return m_linked_section->GetFileAddress() + m_linked_offset;
+ return LLDB_INVALID_ADDRESS;
+}
+
+addr_t
+Section::GetOffset () const
+{
+ if (m_parent)
+ {
+ // This section has a parent which means m_file_addr is an offset.
+ return m_file_addr;
+ }
+
+ // This section has no parent, so there is no offset to be had
+ return 0;
+}
+
+addr_t
+Section::GetByteSize () const
+{
+ return m_byte_size;
+}
+
+void
+Section::SetByteSize (addr_t byte_size)
+{
+ m_byte_size = byte_size;
+}
+
+
+addr_t
+Section::GetLoadBaseAddress (Process *process) const
+{
+ addr_t load_base_addr = LLDB_INVALID_ADDRESS;
+ if (m_linked_section)
+ {
+ load_base_addr = m_linked_section->GetLoadBaseAddress(process) + m_linked_offset;
+ }
+ else
+ if (m_parent)
+ {
+ load_base_addr = m_parent->GetLoadBaseAddress (process);
+ if (load_base_addr != LLDB_INVALID_ADDRESS)
+ load_base_addr += GetOffset();
+ }
+ else
+ {
+ load_base_addr = process->GetSectionLoadAddress(this);
+ }
+
+ return load_base_addr;
+}
+
+bool
+Section::ResolveContainedAddress (addr_t offset, Address &so_addr) const
+{
+ const uint32_t num_children = m_children.GetSize();
+ if (num_children > 0)
+ {
+ for (uint32_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);
+ }
+ }
+ if (m_linked_section)
+ {
+ so_addr.SetOffset(m_linked_offset + offset);
+ so_addr.SetSection(m_linked_section);
+ }
+ else
+ {
+ so_addr.SetOffset(offset);
+ so_addr.SetSection(this);
+ }
+ return true;
+}
+
+uint64_t
+Section::GetFileOffset() const
+{
+ return m_file_offset;
+}
+
+uint64_t
+Section::GetFileSize() const
+{
+ return m_file_size;
+}
+
+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;
+}
+
+bool
+Section::ContainsLinkedFileAddress (addr_t vm_addr) const
+{
+ const addr_t linked_file_addr = GetLinkedFileAddress();
+ if (linked_file_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (linked_file_addr <= vm_addr)
+ {
+ const addr_t offset = vm_addr - linked_file_addr;
+ return offset < GetByteSize();
+ }
+ }
+ return false;
+}
+
+int
+Section::Compare (const Section& a, const Section& b)
+{
+ if (&a == &b)
+ return 0;
+
+ const Module* a_module = a.GetModule();
+ const Module* b_module = b.GetModule();
+ if (a_module == b_module)
+ {
+ 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 < b_module)
+ return -1;
+ else
+ return 1; // We already know the modules aren't equal
+ }
+}
+
+
+void
+Section::Dump(Stream *s, Process *process) const
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ s->Printf("0x%8.8x ", GetID());
+ bool resolved = true;
+ addr_t addr = LLDB_INVALID_ADDRESS;
+
+ if (GetByteSize() == 0)
+ s->Printf("%39s", "");
+ else
+ {
+ if (process)
+ addr = GetLoadBaseAddress (process);
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ if (process)
+ resolved = false;
+ addr = GetFileAddress();
+ }
+
+ VMRange range(addr, addr + m_byte_size);
+ range.Dump (s, 0);
+ }
+
+ s->Printf("%c 0x%8.8llx 0x%8.8llx 0x%8.8x ", resolved ? ' ' : '*', m_file_offset, m_file_size, GetAllFlagBits());
+
+ DumpName (s);
+
+ s->EOL();
+
+ if (m_linked_section)
+ {
+ addr = LLDB_INVALID_ADDRESS;
+
+ if (process)
+ {
+ addr = m_linked_section->GetLoadBaseAddress(process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ addr += m_linked_offset;
+ }
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ if (process)
+ resolved = false;
+ addr = m_linked_section->GetFileAddress() + m_linked_offset;
+ }
+
+ int indent = (sizeof(void*) + 1 + sizeof(user_id_t) + 1) * 2 + 3 + s->GetIndentLevel();
+ s->Printf("%*.*s", indent, indent, "");
+ VMRange linked_range(addr, addr + m_byte_size);
+ linked_range.Dump (s, 0);
+ indent = 3 * (sizeof(uint32_t) * 2 + 2 + 1) + 1;
+ s->Printf("%c%*.*s", resolved ? ' ' : '*', indent, indent, "");
+
+ m_linked_section->DumpName(s);
+ s->Printf(" + 0x%llx\n", m_linked_offset);
+ }
+
+ m_children.Dump(s, process, false);
+}
+
+void
+Section::DumpName (Stream *s) const
+{
+ if (m_linked_section)
+ return m_linked_section->DumpName(s);
+ else if (m_parent == NULL)
+ {
+ // The top most section prints the module basename
+ const char *module_basename = m_module->GetFileSpec().GetFilename().AsCString();
+ if (module_basename && module_basename[0])
+ s->Printf("%s.", module_basename);
+ }
+ else
+ {
+ m_parent->DumpName (s);
+ s->PutChar('.');
+ }
+ m_name.Dump(s);
+}
+
+//----------------------------------------------------------------------
+// Get the section data from a complete contiguous copy of the
+// entire executable image.
+//----------------------------------------------------------------------
+size_t
+Section::GetSectionDataFromImage (const DataExtractor& image_data, DataExtractor& section_data) const
+{
+ size_t file_size = GetByteSize();
+ if (file_size > 0)
+ {
+ off_t file_offset = GetFileOffset();
+ if (section_data.SetData (image_data, file_offset, file_size) == file_size)
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Get the section data the file on disk
+//----------------------------------------------------------------------
+size_t
+Section::ReadSectionDataFromObjectFile(const ObjectFile* objfile, DataExtractor& section_data) const
+{
+ if (objfile == NULL)
+ return 0;
+
+ const FileSpec& file = objfile->GetFileSpec();
+
+ if (file)
+ {
+ size_t section_file_size = GetByteSize();
+ if (section_file_size > 0)
+ {
+ off_t section_file_offset = GetFileOffset() + objfile->GetOffset();
+ DataBufferSP sectionDataSP(file.ReadFileContents(section_file_offset, section_file_size));
+
+ section_data.SetByteOrder(objfile->GetByteOrder());
+ section_data.SetAddressByteSize(objfile->GetAddressByteSize());
+ return section_data.SetData (sectionDataSP);
+ }
+ }
+ return 0;
+}
+
+size_t
+Section::MemoryMapSectionDataFromObjectFile(const ObjectFile* objfile, DataExtractor& section_data) const
+{
+ if (objfile == NULL)
+ return 0;
+
+ const FileSpec& file = objfile->GetFileSpec();
+
+ if (file)
+ {
+ size_t section_file_size = GetFileSize();
+ if (section_file_size > 0)
+ {
+ off_t section_file_offset = GetFileOffset() + objfile->GetOffset();
+ DataBufferSP sectionDataSP(file.MemoryMapFileContents(section_file_offset, section_file_size));
+ section_data.SetByteOrder(objfile->GetByteOrder());
+ section_data.SetAddressByteSize(objfile->GetAddressByteSize());
+ return section_data.SetData (sectionDataSP);
+ }
+ }
+ return 0;
+}
+
+bool
+Section::IsFake() const
+{
+ return m_fake;
+}
+
+void
+Section::SetIsFake(bool fake)
+{
+ m_fake = fake;
+}
+
+
+bool
+Section::IsDescendant (const Section *section)
+{
+ if (this == section)
+ return true;
+ if (m_parent)
+ return m_parent->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;
+}
+
+void
+Section::SetLinkedLocation (const Section *linked_section, uint64_t linked_offset)
+{
+ if (linked_section)
+ m_module = linked_section->GetModule();
+ m_linked_section = linked_section;
+ m_linked_offset = linked_offset;
+}
+
+const Section *
+Section::GetLinkedSection () const
+{
+ return m_linked_section;
+}
+
+uint64_t
+Section::GetLinkedOffset () const
+{
+ return m_linked_offset;
+}
+
+#pragma mark SectionList
+
+SectionList::SectionList () :
+ m_sections()
+{
+}
+
+
+SectionList::~SectionList ()
+{
+}
+
+uint32_t
+SectionList::AddSection (SectionSP& sect_sp)
+{
+ uint32_t section_index = m_sections.size();
+ m_sections.push_back(sect_sp);
+ return section_index;
+}
+
+uint32_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;
+}
+
+uint32_t
+SectionList::AddUniqueSection (SectionSP& sect_sp)
+{
+ uint32_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, 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::GetSize () const
+{
+ return m_sections.size();
+}
+
+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 (uint32_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)
+ {
+ 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)->GetName() == section_dstr)
+ {
+ sect_sp = *sect_iter;
+ }
+ else
+ {
+ sect_sp = (*sect_iter)->GetChildren().FindSectionByName(section_dstr);
+ }
+ }
+ }
+ return sect_sp;
+}
+//
+//SectionSP
+//SectionList::FindSectionByNames (const char *s, ...) const
+//{
+// SectionSP sect_sp;
+// va_list ap;
+// va_start(ap, s);
+// uint32_t idx = 0;
+// for (const char *sect_name = s; sect_name != NULL; sect_name = va_arg(ap, const char *))
+// {
+// printf("[%u] %s\n", idx++, sect_name);
+// }
+// va_end(ap);
+// 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::GetSharedPointer (const Section *section, bool check_children) const
+{
+ SectionSP sect_sp;
+ if (section)
+ {
+ 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->get() == section)
+ {
+ sect_sp = *sect_iter;
+ break;
+ }
+ else if (check_children)
+ {
+ sect_sp = (*sect_iter)->GetChildren().GetSharedPointer (section, true);
+ }
+ }
+ }
+ 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;
+}
+
+
+SectionSP
+SectionList::FindSectionContainingLinkedFileAddress (addr_t vm_addr) 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->ContainsLinkedFileAddress (vm_addr))
+ {
+ sect_sp = *sect_iter;
+ break;
+ }
+ }
+ return sect_sp;
+}
+
+bool
+SectionList::ContainsSection(user_id_t sect_id) const
+{
+ return FindSectionByID (sect_id).get() != NULL;
+}
+
+void
+SectionList::Dump (Stream *s, Process *process, bool show_header) const
+{
+ if (show_header && !m_sections.empty())
+ {
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ s->PutCString( "SectionList\n");
+ s->IndentMore();
+ s->Printf("%*s", 2*(sizeof(void *) + 2), "");
+ s->Indent();
+ s->Printf("SectID %s Address File Off. File Size Flags Section Name\n", process ? "Load" : "File");
+ s->Printf("%*s", 2*(sizeof(void *) + 2), "");
+ 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, process);
+ }
+
+ 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/lldb/source/Core/SourceManager.cpp b/lldb/source/Core/SourceManager.cpp
new file mode 100644
index 00000000000..2786fe40720
--- /dev/null
+++ b/lldb/source/Core/SourceManager.cpp
@@ -0,0 +1,305 @@
+//===-- 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/Core/SourceManager.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb_private;
+
+static inline bool is_newline_char(char ch)
+{
+ return ch == '\n' || ch == '\r';
+}
+
+
+//----------------------------------------------------------------------
+// SourceManager constructor
+//----------------------------------------------------------------------
+SourceManager::SourceManager() :
+ m_file_cache (),
+ m_last_file_sp (),
+ m_last_file_line (0),
+ m_last_file_context_before (0),
+ m_last_file_context_after (0)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SourceManager::~SourceManager()
+{
+}
+
+size_t
+SourceManager::DisplaySourceLines
+(
+ const FileSpec &file_spec,
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ Stream *s
+)
+{
+ m_last_file_sp = GetFile (file_spec);
+ m_last_file_line = line + context_after + 1;
+ m_last_file_context_before = context_before;
+ m_last_file_context_after = context_after;
+ if (m_last_file_sp.get())
+ return m_last_file_sp->DisplaySourceLines (line, context_before, context_after, s);
+
+ return 0;
+}
+
+SourceManager::FileSP
+SourceManager::GetFile (const FileSpec &file_spec)
+{
+ FileSP file_sp;
+ FileCache::iterator pos = m_file_cache.find(file_spec);
+ if (pos != m_file_cache.end())
+ file_sp = pos->second;
+ else
+ {
+ file_sp.reset (new File (file_spec));
+ m_file_cache[file_spec] = file_sp;
+ }
+ return file_sp;
+}
+
+size_t
+SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile
+(
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ const char* current_line_cstr,
+ Stream *s
+)
+{
+ if (line == 0)
+ {
+ if (m_last_file_line != 0
+ && m_last_file_line != UINT32_MAX)
+ line = m_last_file_line + context_before;
+ else
+ line = 1;
+ }
+
+ m_last_file_line = line + context_after + 1;
+ m_last_file_context_before = context_before;
+ m_last_file_context_after = context_after;
+
+ if (context_before == UINT32_MAX)
+ context_before = 0;
+ if (context_after == UINT32_MAX)
+ context_after = 10;
+
+ if (m_last_file_sp.get())
+ {
+ const uint32_t start_line = line <= context_before ? 1 : line - context_before;
+ const uint32_t end_line = line + context_after;
+ uint32_t curr_line;
+ for (curr_line = start_line; curr_line <= end_line; ++curr_line)
+ {
+ if (!m_last_file_sp->LineIsValid (curr_line))
+ {
+ m_last_file_line = UINT32_MAX;
+ break;
+ }
+
+ s->Printf("%4u %2.2s\t", curr_line, curr_line == line ? current_line_cstr : "");
+ if (m_last_file_sp->DisplaySourceLines (curr_line, 0, 0, s) == 0)
+ {
+ m_last_file_line = UINT32_MAX;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+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
+)
+{
+ bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec);
+
+ if (!same_as_previous)
+ m_last_file_sp = GetFile (file_spec);
+
+ if (line == 0)
+ {
+ if (!same_as_previous)
+ m_last_file_line = 0;
+ }
+
+ return DisplaySourceLinesWithLineNumbersUsingLastFile (line, context_before, context_after, current_line_cstr, s);
+}
+
+size_t
+SourceManager::DisplayMoreWithLineNumbers (Stream *s)
+{
+ if (m_last_file_sp)
+ {
+ if (m_last_file_line == UINT32_MAX)
+ return 0;
+ DisplaySourceLinesWithLineNumbersUsingLastFile (0, m_last_file_context_before, m_last_file_context_after, "", s);
+ }
+ return 0;
+}
+
+
+
+SourceManager::File::File(const FileSpec &file_spec) :
+ m_file_spec(file_spec),
+ m_data_sp(file_spec.ReadFileContents ()),
+ m_offsets()
+{
+}
+
+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)
+{
+ 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;
+}
+
+bool
+SourceManager::File::FileSpecMatches (const FileSpec &file_spec)
+{
+ return FileSpec::Compare (m_file_spec, file_spec, false) == 0;
+}
+
+
+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))
+ {
+ 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");
+ }
+
+ }
+ else
+ {
+ // Calculate all line offsets up to "line"
+ assert(!"Not implemented yet");
+ }
+ return false;
+}
diff --git a/lldb/source/Core/State.cpp b/lldb/source/Core/State.cpp
new file mode 100644
index 00000000000..cf9a8345818
--- /dev/null
+++ b/lldb/source/Core/State.cpp
@@ -0,0 +1,87 @@
+//===-- 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"
+
+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 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;
+}
+
+bool
+lldb_private::StateIsRunningState (StateType state)
+{
+ switch (state)
+ {
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ return true;
+
+ case eStateDetached:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ default:
+ break;
+ }
+ return false;
+}
+
+bool
+lldb_private::StateIsStoppedState (StateType state)
+{
+ switch (state)
+ {
+ case eStateInvalid:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ default:
+ break;
+
+ case eStateUnloaded:
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ return true;
+ }
+ return false;
+}
diff --git a/lldb/source/Core/Stream.cpp b/lldb/source/Core/Stream.cpp
new file mode 100644
index 00000000000..a0de2d431e9
--- /dev/null
+++ b/lldb/source/Core/Stream.cpp
@@ -0,0 +1,776 @@
+//===-- 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"
+
+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 (eByteOrderHost),
+ 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".
+//------------------------------------------------------------------
+int
+Stream::PutSLEB128 (int64_t sval)
+{
+ int bytes_written = 0;
+ if (m_flags.IsSet(eBinary))
+ {
+ bool more = true;
+ bool negative = (sval < 0);
+ while (more)
+ {
+ uint8_t byte = sval & 0x7fu;
+ sval >>= 7;
+ assert((!negative && sval >= 0) || (negative && sval < 0));
+ /* 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%lli", sval);
+ }
+
+ return bytes_written;
+
+}
+
+//------------------------------------------------------------------
+// Put an ULEB128 "uval" out to the stream using the printf format
+// in "format".
+//------------------------------------------------------------------
+int
+Stream::PutULEB128 (uint64_t uval)
+{
+ int bytes_written = 0;
+ if (m_flags.IsSet(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%llx", uval);
+ }
+ return bytes_written;
+}
+
+//------------------------------------------------------------------
+// Print a raw NULL terminated C string to the stream using the
+// printf format in "format".
+//------------------------------------------------------------------
+int
+Stream::PutCString (const char *cstr)
+{
+ int cstr_len = strlen(cstr);
+ // when in binary mode, emit the NULL terminator
+ if (m_flags.IsSet(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, int 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*llx%s", prefix, addr_width, addr, suffix);
+ Printf ("%s0x%0*llx%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, int addr_size, const char *prefix, const char *suffix)
+{
+ if (prefix != NULL)
+ PutCString (prefix);
+ Address (lo_addr, addr_size, "[");
+ Address (hi_addr, addr_size, "-", ")");
+}
+
+
+int
+Stream::PutChar (char ch)
+{
+ return Write (&ch, 1);
+}
+
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+int
+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.
+//------------------------------------------------------------------
+int
+Stream::PrintfVarArg (const char *format, va_list args)
+{
+ char str[1024];
+ va_list args_copy;
+
+ va_copy (args_copy, args);
+
+ int bytes_written = 0;
+ // Try and format our string into a fixed buffer first and see if it fits
+ int length = vsnprintf (str, sizeof(str), format, args);
+ if (length < sizeof(str))
+ {
+ va_end (args);
+ // Include the NULL termination byte for binary output
+ if (m_flags.IsSet(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.IsSet(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
+//------------------------------------------------------------------
+int
+Stream::EOL()
+{
+ return PutChar ('\n');
+}
+
+//------------------------------------------------------------------
+// Indent the current line using the current indentation level and
+// print an optional string following the idenatation spaces.
+//------------------------------------------------------------------
+int
+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 ("%lli", 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
+//------------------------------------------------------------------
+uint8_t
+Stream::GetAddressByteSize() const
+{
+ return m_addr_size;
+}
+
+//------------------------------------------------------------------
+// Set the address size in bytes
+//------------------------------------------------------------------
+void
+Stream::SetAddressByteSize(uint8_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.IsSet(eVerbose);
+}
+
+//------------------------------------------------------------------
+// Returns true if the debug flag bit is set in this stream.
+//------------------------------------------------------------------
+bool
+Stream::GetDebug() const
+{
+ return m_flags.IsSet(eDebug);
+}
+
+//------------------------------------------------------------------
+// The flags get accessor
+//------------------------------------------------------------------
+Flags&
+Stream::GetFlags()
+{
+ return m_flags;
+}
+
+//------------------------------------------------------------------
+// The flags const get accessor
+//------------------------------------------------------------------
+const Flags&
+Stream::GetFlags() const
+{
+ return m_flags;
+}
+
+int
+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
+
+ int i;
+ char str[1024];
+ int bytes_written = 0;
+ // Try and format our string into a fixed buffer first and see if it fits
+ int 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 (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 (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;
+}
+
+int
+Stream::PutNHex8 (size_t n, uint8_t uvalue)
+{
+ int bytes_written = 0;
+ for (int i=0; i<n; ++i)
+ bytes_written += _PutHex8 (uvalue, m_flags.IsSet(eAddPrefix));
+ return bytes_written;
+}
+
+int
+Stream::_PutHex8 (uint8_t uvalue, bool add_prefix)
+{
+ int bytes_written = 0;
+ if (m_flags.IsSet(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;
+}
+
+int
+Stream::PutHex8 (uint8_t uvalue)
+{
+ return _PutHex8 (uvalue, m_flags.IsSet(eAddPrefix));
+}
+
+int
+Stream::PutHex16 (uint16_t uvalue, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ bool add_prefix = m_flags.IsSet(eAddPrefix);
+ int bytes_written = 0;
+ int byte;
+ if (byte_order == eByteOrderLittle)
+ {
+ for (byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
+ bytes_written += _PutHex8 (uvalue >> (byte * 8), add_prefix);
+ }
+ else
+ {
+ for (byte = sizeof(uvalue)-1; byte >= 0; --byte, add_prefix = false)
+ bytes_written += _PutHex8 (uvalue >> (byte * 8), add_prefix);
+ }
+ return bytes_written;
+}
+
+int
+Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ bool add_prefix = m_flags.IsSet(eAddPrefix);
+ int bytes_written = 0;
+ int byte;
+ if (byte_order == eByteOrderLittle)
+ {
+ for (byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
+ bytes_written += _PutHex8 (uvalue >> (byte * 8), add_prefix);
+ }
+ else
+ {
+ for (byte = sizeof(uvalue)-1; byte >= 0; --byte, add_prefix = false)
+ bytes_written += _PutHex8 (uvalue >> (byte * 8), add_prefix);
+ }
+ return bytes_written;
+}
+
+int
+Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ bool add_prefix = m_flags.IsSet(eAddPrefix);
+ int bytes_written = 0;
+ int byte;
+ if (byte_order == eByteOrderLittle)
+ {
+ for (byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
+ bytes_written += _PutHex8 (uvalue >> (byte * 8), add_prefix);
+ }
+ else
+ {
+ for (byte = sizeof(uvalue)-1; byte >= 0; --byte, add_prefix = false)
+ bytes_written += _PutHex8 (uvalue >> (byte * 8), add_prefix);
+ }
+ return bytes_written;
+}
+
+int
+Stream::PutMaxHex64
+(
+ uint64_t uvalue,
+ size_t byte_size,
+ lldb::ByteOrder byte_order
+)
+{
+ switch (byte_size)
+ {
+ case 1: return PutHex8 (uvalue);
+ case 2: return PutHex16 (uvalue);
+ case 4: return PutHex32 (uvalue);
+ case 8: return PutHex64 (uvalue);
+ }
+ return 0;
+}
+
+int
+Stream::PutPointer (void *ptr)
+{
+ return PutRawBytes (&ptr, sizeof(ptr), eByteOrderHost, eByteOrderHost);
+}
+
+int
+Stream::PutFloat(float f, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes (&f, sizeof(f), eByteOrderHost, byte_order);
+}
+
+int
+Stream::PutDouble(double d, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes (&d, sizeof(d), eByteOrderHost, byte_order);
+}
+
+int
+Stream::PutLongDouble(long double ld, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes (&ld, sizeof(ld), eByteOrderHost, byte_order);
+}
+
+int
+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;
+
+ int bytes_written = 0;
+ const uint8_t *src = (const uint8_t *)s;
+ int i;
+ bool binary_is_clear = m_flags.IsClear (eBinary);
+ m_flags.Set (eBinary);
+ if (src_byte_order == dst_byte_order)
+ {
+ for (i=0;i<src_len; ++i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ else
+ {
+ for (i=src_len-1;i>=0; --i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ if (binary_is_clear)
+ m_flags.Clear (eBinary);
+
+ return bytes_written;
+}
+
+int
+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;
+
+ int bytes_written = 0;
+ const uint8_t *src = (const uint8_t *)s;
+ int i;
+ bool binary_is_set = m_flags.IsSet(eBinary);
+ m_flags.Clear(eBinary);
+ if (src_byte_order == dst_byte_order)
+ {
+ for (i=0;i<src_len; ++i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ else
+ {
+ for (i=src_len-1;i>=0; --i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+
+ return bytes_written;
+}
+
+int
+Stream::PutCStringAsRawHex8 (const char *s)
+{
+ int bytes_written = 0;
+ bool binary_is_set = m_flags.IsSet(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, eByteOrderHost);
+ s->PutChar(' ');
+ s->PutHex16(0x3456, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex16(0x3456, eByteOrderLittle);
+
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderHost);
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderLittle);
+
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, eByteOrderHost);
+ 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/lldb/source/Core/StreamFile.cpp b/lldb/source/Core/StreamFile.cpp
new file mode 100644
index 00000000000..9c6c508b49e
--- /dev/null
+++ b/lldb/source/Core/StreamFile.cpp
@@ -0,0 +1,132 @@
+//===-- 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
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// StreamFile constructor
+//----------------------------------------------------------------------
+StreamFile::StreamFile () :
+ Stream (),
+ m_file (NULL),
+ m_path_name (),
+ m_close_file (false)
+{
+}
+
+StreamFile::StreamFile(uint32_t flags, uint32_t addr_size, ByteOrder byte_order, FILE *f) :
+ Stream (flags, addr_size, byte_order),
+ m_file(f),
+ m_path_name (),
+ m_close_file(false)
+{
+}
+
+StreamFile::StreamFile(FILE *f) :
+ Stream (),
+ m_file(f),
+ m_path_name (),
+ m_close_file(false)
+{
+}
+
+StreamFile::StreamFile(uint32_t flags, uint32_t addr_size, ByteOrder byte_order, const char *path, const char *permissions) :
+ Stream (flags, addr_size, byte_order),
+ m_file (NULL),
+ m_path_name (path),
+ m_close_file(false)
+{
+ Open(path, permissions);
+}
+
+StreamFile::StreamFile(const char *path, const char *permissions) :
+ Stream (),
+ m_file (NULL),
+ m_path_name (path),
+ m_close_file(false)
+{
+ Open(path, permissions);
+}
+
+
+StreamFile::~StreamFile()
+{
+ Close ();
+}
+
+void
+StreamFile::Close ()
+{
+ if (m_close_file && m_file != NULL)
+ ::fclose (m_file);
+ m_file = NULL;
+ m_close_file = false;
+}
+
+bool
+StreamFile::Open (const char *path, const char *permissions)
+{
+ Close();
+ if (path && path[0])
+ {
+ if ((m_path_name.size() == 0)
+ || (m_path_name.compare(path) != 0))
+ m_path_name = path;
+ m_file = ::fopen (path, permissions);
+ if (m_file != NULL)
+ m_close_file = true;
+ }
+ return m_file != NULL;
+}
+
+void
+StreamFile::Flush ()
+{
+ if (m_file)
+ ::fflush (m_file);
+}
+
+int
+StreamFile::Write (const void *s, size_t length)
+{
+ if (m_file)
+ return ::fwrite (s, 1, length, m_file);
+ return 0;
+}
+
+FILE *
+StreamFile::GetFileHandle()
+{
+ return m_file;
+}
+
+void
+StreamFile::SetFileHandle (FILE *file, bool close_file)
+{
+ Close();
+ m_file = file;
+ m_close_file = close_file;
+}
+
+const char *
+StreamFile::GetFilePathname ()
+{
+ if (m_path_name.size() == 0)
+ return NULL;
+ else
+ return m_path_name.c_str();
+}
diff --git a/lldb/source/Core/StreamString.cpp b/lldb/source/Core/StreamString.cpp
new file mode 100644
index 00000000000..ccd9f972582
--- /dev/null
+++ b/lldb/source/Core/StreamString.cpp
@@ -0,0 +1,81 @@
+//===-- 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 <libkern/OSByteOrder.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...
+}
+
+int
+StreamString::Write (const void *s, size_t length)
+{
+ m_packet.append ((char *)s, length);
+ return length;
+}
+
+void
+StreamString::Clear()
+{
+ m_packet.clear();
+}
+
+void
+StreamString::Dump(FILE *f)
+{
+ int size = GetSize();
+ if (size > 0)
+ fprintf(f, "%*.*s", size, size, m_packet.c_str());
+}
+
+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;
+}
+
diff --git a/lldb/source/Core/StringList.cpp b/lldb/source/Core/StringList.cpp
new file mode 100644
index 00000000000..cb96fb0f7b9
--- /dev/null
+++ b/lldb/source/Core/StringList.cpp
@@ -0,0 +1,200 @@
+//===-- 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 <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 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)
+{
+ uint32_t len = strings.GetSize();
+
+ for (int i = 0; i < len; ++i)
+ m_strings.push_back (strings.GetStringAtIndex(i));
+}
+
+uint32_t
+StringList::GetSize ()
+{
+ return m_strings.size();
+}
+
+const char *
+StringList::GetStringAtIndex (size_t idx)
+{
+ if (idx < m_strings.size())
+ return m_strings[idx].c_str();
+ return NULL;
+}
+
+void
+StringList::Clear ()
+{
+ m_strings.clear();
+}
+
+void
+StringList::LongestCommonPrefix (std::string &common_prefix)
+{
+ //arg_sstr_collection::iterator pos, end = m_args.end();
+ int pos = 0;
+ int end = m_strings.size();
+
+ if (pos == end)
+ common_prefix.clear();
+ else
+ common_prefix = m_strings[pos];
+
+ for (++pos; pos != end; ++pos)
+ {
+ int 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 (int 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;
+
+ int idx = 0;
+ while (idx < m_strings.size())
+ {
+ if (m_strings[idx].empty())
+ DeleteStringAtIndex(idx);
+ else
+ idx++;
+ }
+}
diff --git a/lldb/source/Core/TTYState.cpp b/lldb/source/Core/TTYState.cpp
new file mode 100644
index 00000000000..6ba415832d4
--- /dev/null
+++ b/lldb/source/Core/TTYState.cpp
@@ -0,0 +1,203 @@
+//===-- TTYState.cpp --------------------------------------------*- 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/TTYState.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/signal.h>
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+TTYState::TTYState() :
+ m_fd(-1),
+ m_tflags(-1),
+ m_ttystate_err(-1),
+ m_ttystate(),
+ m_process_group(-1)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+TTYState::~TTYState()
+{
+}
+
+//----------------------------------------------------------------------
+// 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
+TTYState::Save (int fd, bool save_process_group)
+{
+ if (fd >= 0 && ::isatty (fd))
+ {
+ m_fd = fd;
+ m_tflags = ::fcntl (fd, F_GETFL, 0);
+ m_ttystate_err = ::tcgetattr (fd, &m_ttystate);
+ if (save_process_group)
+ m_process_group = ::tcgetpgrp (0);
+ else
+ m_process_group = -1;
+ }
+ else
+ {
+ m_fd = -1;
+ m_tflags = -1;
+ m_ttystate_err = -1;
+ m_process_group = -1;
+ }
+ return m_ttystate_err == 0;
+}
+
+//----------------------------------------------------------------------
+// Restore the state of the TTY using the cached values from a
+// previous call to Save().
+//----------------------------------------------------------------------
+bool
+TTYState::Restore () const
+{
+ int result = 0;
+ if (IsValid())
+ {
+ if (TFlagsIsValid())
+ result = fcntl (m_fd, F_SETFL, m_tflags);
+
+ if (TTYStateIsValid())
+ result = tcsetattr (m_fd, TCSANOW, &m_ttystate);
+
+ 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
+ result = tcsetpgrp (m_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
+TTYState::IsValid() const
+{
+ return (m_fd >= 0) && (TFlagsIsValid() || TTYStateIsValid());
+}
+
+//----------------------------------------------------------------------
+// Returns true if m_tflags is valid
+//----------------------------------------------------------------------
+bool
+TTYState::TFlagsIsValid() const
+{
+ return m_tflags != -1;
+}
+
+//----------------------------------------------------------------------
+// Returns true if m_ttystate is valid
+//----------------------------------------------------------------------
+bool
+TTYState::TTYStateIsValid() const
+{
+ return m_ttystate_err == 0;
+}
+
+//----------------------------------------------------------------------
+// Returns true if m_process_group is valid
+//----------------------------------------------------------------------
+bool
+TTYState::ProcessGroupIsValid() const
+{
+ return m_process_group != -1;
+}
+
+//------------------------------------------------------------------
+// Constructor
+//------------------------------------------------------------------
+TTYStateSwitcher::TTYStateSwitcher () :
+ m_currentState(UINT32_MAX)
+{
+}
+
+//------------------------------------------------------------------
+// Destructor
+//------------------------------------------------------------------
+TTYStateSwitcher::~TTYStateSwitcher ()
+{
+}
+
+//------------------------------------------------------------------
+// Returns the number of states that this switcher contains
+//------------------------------------------------------------------
+uint32_t
+TTYStateSwitcher::GetNumberOfStates() const
+{
+ return sizeof(m_ttystates)/sizeof(TTYState);
+}
+
+//------------------------------------------------------------------
+// Restore the state at index "idx".
+//
+// Returns true if the restore was successful, false otherwise.
+//------------------------------------------------------------------
+bool
+TTYStateSwitcher::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
+TTYStateSwitcher::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/lldb/source/Core/Timer.cpp b/lldb/source/Core/Timer.cpp
new file mode 100644
index 00000000000..e0d3bab354a
--- /dev/null
+++ b/lldb/source/Core/Timer.cpp
@@ -0,0 +1,235 @@
+//===-- 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 "lldb/Core/Stream.h"
+#include "lldb/Host/Mutex.h"
+
+using namespace lldb_private;
+
+#define TIMER_INDENT_AMOUNT 2
+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> CategoryMap;
+static pthread_key_t g_key;
+
+
+static Mutex &
+GetCategoryMutex()
+{
+ static Mutex g_category_mutex(Mutex::eMutexTypeNormal);
+ return g_category_mutex;
+}
+
+static CategoryMap &
+GetCategoryMap()
+{
+ static CategoryMap 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::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)
+ {
+ // 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();
+ bool notify = false;
+ if (m_total_start.IsValid())
+ {
+ m_total_ticks += (stop_time - m_total_start);
+ m_total_start.Clear();
+ notify = true;
+ }
+ 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;
+ ::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());
+ CategoryMap &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 CategoryMap::const_iterator& lhs, const CategoryMap::const_iterator& rhs)
+{
+ return lhs->second > rhs->second;
+}
+
+
+void
+Timer::ResetCategoryTimes ()
+{
+ Mutex::Locker locker (GetCategoryMutex());
+ CategoryMap &category_map = GetCategoryMap();
+ category_map.clear();
+}
+
+void
+Timer::DumpCategoryTimes (Stream *s)
+{
+ Mutex::Locker locker (GetCategoryMutex());
+ CategoryMap &category_map = GetCategoryMap();
+ std::vector<CategoryMap::const_iterator> sorted_iterators;
+ CategoryMap::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);
+ }
+} \ No newline at end of file
diff --git a/lldb/source/Core/UUID.cpp b/lldb/source/Core/UUID.cpp
new file mode 100644
index 00000000000..1ccfdccfab0
--- /dev/null
+++ b/lldb/source/Core/UUID.cpp
@@ -0,0 +1,218 @@
+//===-- 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
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+
+using namespace lldb_private;
+
+UUID::UUID()
+{
+ ::bzero (m_uuid, sizeof(m_uuid));
+}
+
+UUID::UUID(const UUID& rhs)
+{
+ ::memcpy (m_uuid, rhs.m_uuid, sizeof (m_uuid));
+}
+
+UUID::UUID (const void *uuid_bytes, uint32_t num_uuid_bytes)
+{
+ if (uuid_bytes && num_uuid_bytes >= 16)
+ ::memcpy (m_uuid, uuid_bytes, sizeof (m_uuid));
+ else
+ ::bzero (m_uuid, sizeof(m_uuid));
+}
+
+UUID::UUID (const uuid_t *uuid)
+{
+ if (uuid)
+ ::memcpy (m_uuid, uuid, sizeof (m_uuid));
+ else
+ ::bzero (m_uuid, sizeof(m_uuid));
+}
+
+const UUID&
+UUID::operator=(const UUID& rhs)
+{
+ if (this != &rhs)
+ ::memcpy (m_uuid, rhs.m_uuid, sizeof (m_uuid));
+ return *this;
+}
+
+UUID::~UUID()
+{
+}
+
+void
+UUID::Clear()
+{
+ ::bzero (m_uuid, sizeof(m_uuid));
+}
+
+const void *
+UUID::GetBytes() const
+{
+ return m_uuid;
+}
+
+char *
+UUID::GetAsCString (char *dst, size_t dst_len) const
+{
+ const uint8_t *u = (const uint8_t *)GetBytes();
+ snprintf(dst, dst_len, "%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]);
+ return dst;
+}
+
+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]);
+}
+
+void
+UUID::SetBytes (const void *uuid_bytes)
+{
+ if (uuid_bytes)
+ ::memcpy (m_uuid, uuid_bytes, sizeof (m_uuid));
+ else
+ ::bzero (m_uuid, sizeof(m_uuid));
+}
+
+size_t
+UUID::GetByteSize()
+{
+ return sizeof(UUID::ValueType);
+}
+
+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];
+}
+
+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::SetfromCString (const char *cstr)
+{
+ if (cstr == NULL)
+ return 0;
+
+ uint32_t uuid_byte_idx = 0;
+ const char *p = cstr;
+
+ // Skip leading whitespace characters
+ while (isspace(*p))
+ ++p;
+
+ // Try and decode a UUID
+ while (*p != '\0')
+ {
+ if (isxdigit(*p) && 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
+ m_uuid[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 == 16)
+ break;
+ }
+ else if (*p == '-')
+ {
+ // Skip dashes
+ p++;
+ }
+ else
+ {
+ // UUID values can only consist of hex characters and '-' chars
+ return 0;
+ }
+ }
+ // If we successfully decoded a UUID, return the amount of characters that
+ // were consumed
+ if (uuid_byte_idx == 16)
+ return p - cstr;
+
+ // Else return zero to indicate we were not able to parse a UUID value
+ return 0;
+}
+
+
+
+bool
+lldb_private::operator == (const UUID &lhs, const UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), UUID::GetByteSize()) == 0;
+}
+
+bool
+lldb_private::operator != (const UUID &lhs, const UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), UUID::GetByteSize()) != 0;
+}
+
+bool
+lldb_private::operator < (const UUID &lhs, const UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), UUID::GetByteSize()) < 0;
+}
+
+bool
+lldb_private::operator <= (const UUID &lhs, const UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), UUID::GetByteSize()) <= 0;
+}
+
+bool
+lldb_private::operator > (const UUID &lhs, const UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), UUID::GetByteSize()) > 0;
+}
+
+bool
+lldb_private::operator >= (const UUID &lhs, const UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), UUID::GetByteSize()) >= 0;
+}
diff --git a/lldb/source/Core/UserID.cpp b/lldb/source/Core/UserID.cpp
new file mode 100644
index 00000000000..b1dd5a618c1
--- /dev/null
+++ b/lldb/source/Core/UserID.cpp
@@ -0,0 +1,73 @@
+//===-- 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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UserID::UserID (user_id_t uid) :
+ m_uid(uid)
+{
+}
+
+UserID::~UserID ()
+{
+}
+
+void
+UserID::Clear ()
+{
+ m_uid = LLDB_INVALID_UID;
+}
+
+
+user_id_t
+UserID::GetID () const
+{
+ return m_uid;
+}
+
+void
+UserID::SetID (user_id_t uid)
+{
+ m_uid = uid;
+}
+
+UserID::IDMatches::IDMatches (user_id_t uid) :
+ m_uid(uid)
+{
+}
+
+bool
+UserID::IDMatches::operator() (const UserID& rhs) const
+{
+ return m_uid == rhs.GetID();
+}
+
+Stream&
+lldb_private::operator << (Stream& strm, const UserID& uid)
+{
+ strm.Printf("{0x%8.8x}", uid.GetID());
+ return strm;
+}
+
+bool
+lldb_private::operator== (const UserID& lhs, const UserID& rhs)
+{
+ return lhs.GetID() == rhs.GetID();
+}
+
+bool
+lldb_private::operator!= (const UserID& lhs, const UserID& rhs)
+{
+ return lhs.GetID() != rhs.GetID();
+}
+
diff --git a/lldb/source/Core/VMRange.cpp b/lldb/source/Core/VMRange.cpp
new file mode 100644
index 00000000000..2f5d8ecf9ab
--- /dev/null
+++ b/lldb/source/Core/VMRange.cpp
@@ -0,0 +1,100 @@
+//===-- 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"
+
+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;
+}
+
+
+void
+VMRange::Dump(Stream *s, lldb::addr_t offset) const
+{
+ s->AddressRange(offset + GetBaseAddress(), offset + GetEndAddress(), sizeof (addr_t));
+}
+
+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/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp
new file mode 100644
index 00000000000..c4c17dd0428
--- /dev/null
+++ b/lldb/source/Core/Value.cpp
@@ -0,0 +1,803 @@
+//===-- 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/Stream.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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Value::Value() :
+ m_value(),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(const Scalar& scalar) :
+ m_value(scalar),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(int v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(unsigned int v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(long v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(unsigned long v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(long long v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(unsigned long long v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(float v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(double v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(long double v) :
+ m_value(v),
+ m_value_type(eValueTypeScalar),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+}
+
+Value::Value(const uint8_t *bytes, int len) :
+ m_value(),
+ m_value_type(eValueTypeHostAddress),
+ m_context(NULL),
+ m_context_type(eContextTypeInvalid)
+{
+ 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_value_type(v.m_value_type),
+ m_context(v.m_context),
+ m_context_type(v.m_context_type)
+{
+ 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::CreateProxy()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->CreateProxy ();
+
+ Value *ret = new Value;
+ ret->SetContext(eContextTypeValue, this);
+ return ret;
+}
+
+Value *
+Value::GetProxyTarget()
+{
+ if (m_context_type == eContextTypeValue)
+ return (Value*)m_context;
+ else
+ return NULL;
+}
+
+//#include "clang/Lex/LiteralSupport.h"
+//#include "clang/AST/ASTContext.h"
+//#include "clang/Frontend/CompilerInstance.h"
+//
+//Value::Value (const char *data, llvm::CompilerInstance *compiler)
+//{
+// clang::NumericLiteralParser parser(data, data + strlen(data), clang::SourceLocation(),
+// compiler->getPreprocessor());
+// if (parser.had_error)
+// {
+// }
+// else if (parser.isBool)
+// {
+// APInt value;
+// parser.GetIntegerValue(value);
+// }
+// else if (parser.isLong)
+// {
+// }
+// else if (parser.isLongLong)
+// {
+// }
+// else if (parser.isFloat)
+// {
+// }
+//
+//}
+//
+void
+Value::Dump (Stream* strm)
+{
+ if (m_context_type == eContextTypeValue)
+ {
+ ((Value*)m_context)->Dump (strm);
+ return;
+ }
+
+ 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));
+}
+
+void *
+Value::GetOpaqueClangQualType()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetOpaqueClangQualType ();
+
+ if (m_context_type == eContextTypeOpaqueClangQualType)
+ return m_context;
+
+ return NULL;
+}
+
+Value::ValueType
+Value::GetValueType() const
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetValueType ();
+
+ return m_value_type;
+}
+
+lldb::AddressType
+Value::GetValueAddressType () const
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetValueAddressType ();
+
+ switch (m_value_type)
+ {
+ default:
+ case eValueTypeScalar:
+ break;
+ case eValueTypeLoadAddress: return eAddressTypeLoad;
+ case eValueTypeFileAddress: return eAddressTypeFile;
+ case eValueTypeHostAddress: return eAddressTypeHost;
+ }
+ return eAddressTypeInvalid;
+}
+
+
+Value::ContextType
+Value::GetContextType() const
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetContextType ();
+
+ return m_context_type;
+}
+
+void
+Value::SetValueType (Value::ValueType value_type)
+{
+ if (m_context_type == eContextTypeValue)
+ {
+ ((Value*)m_context)->SetValueType(value_type);
+ return;
+ }
+
+ m_value_type = value_type;
+}
+
+void
+Value::ClearContext ()
+{
+ if (m_context_type == eContextTypeValue)
+ {
+ ((Value*)m_context)->ClearContext();
+ return;
+ }
+
+ m_context = NULL;
+ m_context_type = eContextTypeInvalid;
+}
+
+void
+Value::SetContext (Value::ContextType context_type, void *p)
+{
+ if (m_context_type == eContextTypeValue)
+ {
+ ((Value*)m_context)->SetContext(context_type, p);
+ return;
+ }
+
+ m_context_type = context_type;
+ m_context = p;
+}
+
+RegisterInfo *
+Value::GetRegisterInfo()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetRegisterInfo();
+
+ if (m_context_type == eContextTypeDCRegisterInfo)
+ return static_cast<RegisterInfo *> (m_context);
+ return NULL;
+}
+
+Type *
+Value::GetType()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetType();
+
+ if (m_context_type == eContextTypeDCType)
+ return static_cast<Type *> (m_context);
+ return NULL;
+}
+
+Scalar &
+Value::GetScalar()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetScalar();
+
+ return m_value;
+}
+
+void
+Value::ResizeData(int len)
+{
+ if (m_context_type == eContextTypeValue)
+ {
+ ((Value*)m_context)->ResizeData(len);
+ return;
+ }
+
+ m_value_type = eValueTypeHostAddress;
+ m_data_buffer.SetByteSize(len);
+ m_value = (uintptr_t)m_data_buffer.GetBytes();
+}
+
+bool
+Value::ValueOf(ExecutionContext *exe_ctx, clang::ASTContext *ast_context)
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->ValueOf(exe_ctx, ast_context);
+
+ switch (m_context_type)
+ {
+ default:
+ case eContextTypeInvalid:
+ case eContextTypeOpaqueClangQualType: // clang::Type *
+ case eContextTypeDCRegisterInfo: // RegisterInfo *
+ case eContextTypeDCType: // Type *
+ break;
+
+ case eContextTypeDCVariable: // Variable *
+ ResolveValue(exe_ctx, ast_context);
+ return true;
+ }
+ return false;
+}
+
+size_t
+Value::GetValueByteSize (clang::ASTContext *ast_context, Error *error_ptr)
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetValueByteSize(ast_context, error_ptr);
+
+ size_t byte_size = 0;
+
+ switch (m_context_type)
+ {
+ default:
+ case eContextTypeInvalid:
+ // If we have no context, there is no way to know how much memory to read
+ if (error_ptr)
+ error_ptr->SetErrorString ("Invalid context type, there is no way to know how much memory to read.");
+ break;
+
+ case eContextTypeOpaqueClangQualType:
+ if (ast_context == NULL)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("Can't determine size of opaque clang type with NULL ASTContext *.");
+ }
+ else
+ {
+ uint64_t bit_width = ClangASTContext::GetTypeBitSize (ast_context, m_context);
+ byte_size = (bit_width + 7 ) / 8;
+ }
+ break;
+
+ case eContextTypeDCRegisterInfo: // RegisterInfo *
+ if (GetRegisterInfo())
+ byte_size = GetRegisterInfo()->byte_size;
+ else if (error_ptr)
+ error_ptr->SetErrorString ("Can't determine byte size with NULL RegisterInfo *.");
+
+ break;
+
+ case eContextTypeDCType: // Type *
+ if (GetType())
+ byte_size = GetType()->GetByteSize();
+ else if (error_ptr)
+ error_ptr->SetErrorString ("Can't determine byte size with NULL Type *.");
+ break;
+
+ case eContextTypeDCVariable: // Variable *
+ if (GetVariable())
+ byte_size = GetVariable()->GetType()->GetByteSize();
+ else if (error_ptr)
+ error_ptr->SetErrorString ("Can't determine byte size with NULL Variable *.");
+ 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;
+}
+
+void *
+Value::GetValueOpaqueClangQualType ()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetValueOpaqueClangQualType();
+
+ switch (m_context_type)
+ {
+ default:
+ case eContextTypeInvalid:
+ break;
+
+ case eContextTypeOpaqueClangQualType:
+ return m_context;
+
+ case eContextTypeDCRegisterInfo:
+ break; // TODO: Eventually convert into a clang type?
+
+ case eContextTypeDCType:
+ if (GetType())
+ return GetType()->GetOpaqueClangQualType();
+ break;
+
+ case eContextTypeDCVariable:
+ if (GetVariable())
+ return GetVariable()->GetType()->GetOpaqueClangQualType();
+ break;
+ }
+
+ return NULL;
+}
+
+lldb::Format
+Value::GetValueDefaultFormat ()
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetValueDefaultFormat();
+
+ switch (m_context_type)
+ {
+ default:
+ case eContextTypeInvalid:
+ break;
+
+ case eContextTypeOpaqueClangQualType:
+ return Type::GetFormat (m_context);
+
+ case eContextTypeDCRegisterInfo:
+ if (GetRegisterInfo())
+ return GetRegisterInfo()->format;
+ break;
+
+ case eContextTypeDCType:
+ if (GetType())
+ return GetType()->GetFormat();
+ break;
+
+ case eContextTypeDCVariable:
+ if (GetVariable())
+ return GetVariable()->GetType()->GetFormat();
+ break;
+
+ }
+
+ // Return a good default in case we can't figure anything out
+ return eFormatHex;
+}
+
+Error
+Value::GetValueAsData (ExecutionContext *exe_ctx, clang::ASTContext *ast_context, DataExtractor &data, uint32_t data_offset)
+{
+ if (m_context_type == eContextTypeValue)
+ return ((Value*)m_context)->GetValueAsData(exe_ctx, ast_context, data, data_offset);
+
+ data.Clear();
+
+ Error error;
+ lldb::addr_t address = LLDB_INVALID_ADDRESS;
+ lldb::AddressType address_type = eAddressTypeFile;
+ switch (m_value_type)
+ {
+ default:
+ error.SetErrorStringWithFormat("Invalid value type %i.\n", m_value_type);
+ break;
+
+ case eValueTypeScalar:
+ data.SetByteOrder (eByteOrderHost);
+ data.SetAddressByteSize(sizeof(void *));
+ if (m_value.GetData (data))
+ return error; // Success;
+ error.SetErrorStringWithFormat("Extracting data from value failed.\n");
+ break;
+
+ case eValueTypeLoadAddress:
+ if (exe_ctx == NULL)
+ {
+ error.SetErrorString ("Can't read memory (no execution context).");
+ }
+ else if (exe_ctx->process == NULL)
+ {
+ error.SetErrorString ("Can't read memory (invalid process).");
+ }
+ else
+ {
+ address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ address_type = eAddressTypeLoad;
+ data.SetByteOrder(exe_ctx->process->GetByteOrder());
+ data.SetAddressByteSize(exe_ctx->process->GetAddressByteSize());
+ }
+ break;
+
+ case eValueTypeFileAddress:
+ {
+ // 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 (GetVariable())
+ {
+ lldb::addr_t file_addr = m_value.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());
+ address = so_addr.GetLoadAddress (exe_ctx->process);
+ if (address != LLDB_INVALID_ADDRESS)
+ address_type = eAddressTypeLoad;
+ }
+ if (address_type == eAddressTypeFile)
+ error.SetErrorStringWithFormat ("%s is not loaded.\n", var_sc.module_sp->GetFileSpec().GetFilename().AsCString());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Unable to resolve the module for file address 0x%llx for variable '%s'.\n", file_addr, variable->GetName().AsCString(""));
+ }
+ }
+ else
+ {
+ error.SetErrorString ("Invalid file 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);
+ data.SetByteOrder(eByteOrderHost);
+ data.SetAddressByteSize(sizeof(void *));
+ address_type = eAddressTypeHost;
+ break;
+ }
+
+ // Bail if we encountered any errors
+ if (error.Fail())
+ return error;
+
+ if (address == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorStringWithFormat ("Invalid %s address.\n", address_type == eAddressTypeHost ? "host" : "load");
+ return error;
+ }
+
+ // If we got here, we need to read the value from memory
+ uint32_t byte_size = GetValueByteSize (ast_context, &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 = (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)
+ {
+ if (exe_ctx->process->ReadMemory(address, dst, byte_size, error) != byte_size)
+ {
+ if (error.Success())
+ error.SetErrorStringWithFormat("read %u bytes of memory from 0x%llx failed", (uint64_t)address, byte_size);
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Unsupported lldb::AddressType value (%i).\n", address_type);
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Out of memory.\n");
+ }
+
+ return error;
+}
+
+Scalar &
+Value::ResolveValue(ExecutionContext *exe_ctx, clang::ASTContext *ast_context)
+{
+ Scalar scalar;
+ if (m_context_type == eContextTypeValue)
+ {
+ // Resolve the proxy
+
+ Value * v = (Value*)m_context;
+
+ m_value = v->m_value;
+ m_value_type = v->m_value_type;
+ m_context = v->m_context;
+ m_context_type = v->m_context_type;
+
+ 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();
+ }
+ }
+
+ if (m_context_type == eContextTypeOpaqueClangQualType)
+ {
+ void *opaque_clang_qual_type = GetOpaqueClangQualType();
+ switch (m_value_type)
+ {
+ case eValueTypeScalar: // raw scalar value
+ break;
+
+ default:
+ case eValueTypeFileAddress:
+ m_value.Clear();
+ break;
+
+ case eValueTypeLoadAddress: // load address value
+ case eValueTypeHostAddress: // host address value (for memory in the process that is using liblldb)
+ {
+ lldb::AddressType address_type = m_value_type == eValueTypeLoadAddress ? eAddressTypeLoad : eAddressTypeHost;
+ lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ DataExtractor data;
+ if (Type::ReadFromMemory (exe_ctx, ast_context, opaque_clang_qual_type, addr, address_type, data))
+ {
+ if (Type::GetValueAsScalar (ast_context, opaque_clang_qual_type, 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 == eContextTypeValue)
+ return ((Value*)m_context)->GetVariable();
+
+ if (m_context_type == eContextTypeDCVariable)
+ return static_cast<Variable *> (m_context);
+ return NULL;
+}
+
+
+
+const char *
+Value::GetValueTypeAsCString (ValueType value_type)
+{
+ switch (value_type)
+ {
+ case eValueTypeScalar: return "scalar";
+ 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 eContextTypeOpaqueClangQualType: return "clang::Type *";
+ case eContextTypeDCRegisterInfo: return "RegisterInfo *";
+ case eContextTypeDCType: return "Type *";
+ case eContextTypeDCVariable: 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/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
new file mode 100644
index 00000000000..93511febe8a
--- /dev/null
+++ b/lldb/source/Core/ValueObject.cpp
@@ -0,0 +1,678 @@
+//===-- 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/Core/ValueObject.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "clang/AST/Type.h"
+#include "llvm/Support/raw_ostream.h"
+
+// Project includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Core/ValueObjectList.h"
+
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Type.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static lldb::user_id_t g_value_obj_uid = 0;
+
+//----------------------------------------------------------------------
+// ValueObject constructor
+//----------------------------------------------------------------------
+ValueObject::ValueObject () :
+ UserID (++g_value_obj_uid), // Unique identifier for every value object
+ m_update_id (0), // Value object lists always start at 1, value objects start at zero
+ m_name (),
+ m_data (),
+ m_value (),
+ m_error (),
+ m_flags (),
+ m_value_str(),
+ m_location_str(),
+ m_summary_str(),
+ m_children(),
+ m_synthetic_children()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ValueObject::~ValueObject ()
+{
+}
+
+user_id_t
+ValueObject::GetUpdateID() const
+{
+ return m_update_id;
+}
+
+bool
+ValueObject::UpdateValueIfNeeded (ExecutionContextScope *exe_scope)
+{
+ if (exe_scope)
+ {
+ Process *process = exe_scope->CalculateProcess();
+ if (process)
+ {
+ const user_id_t stop_id = process->GetStopID();
+ if (m_update_id != stop_id)
+ {
+ m_value_str.clear();
+ m_location_str.clear();
+ m_summary_str.clear();
+
+ UpdateValue (exe_scope);
+ if (m_error.Success())
+ m_update_id = stop_id;
+ }
+ }
+ }
+ return m_error.Success();
+}
+
+const DataExtractor &
+ValueObject::GetDataExtractor () const
+{
+ return m_data;
+}
+
+DataExtractor &
+ValueObject::GetDataExtractor ()
+{
+ return m_data;
+}
+
+const Error &
+ValueObject::GetError() const
+{
+ return m_error;
+}
+
+const ConstString &
+ValueObject::GetName() const
+{
+ return m_name;
+}
+
+const char *
+ValueObject::GetLocationAsCString (ExecutionContextScope *exe_scope)
+{
+ if (UpdateValueIfNeeded(exe_scope))
+ {
+ if (m_location_str.empty())
+ {
+ StreamString sstr;
+
+ switch (m_value.GetValueType())
+ {
+ default:
+ break;
+
+ case Value::eValueTypeScalar:
+ if (m_value.GetContextType() == Value::eContextTypeDCRegisterInfo)
+ {
+ RegisterInfo *reg_info = m_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;
+ break;
+ }
+ }
+ m_location_str = "scalar";
+ break;
+
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeHostAddress:
+ {
+ uint32_t addr_nibble_size = m_data.GetAddressByteSize() * 2;
+ sstr.Printf("0x%*.*llx", addr_nibble_size, addr_nibble_size, m_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::GetValueIsValid ()
+{
+ return m_flags.IsSet(eValueIsValid);
+}
+
+
+void
+ValueObject::SetValueIsValid (bool b)
+{
+ if (b)
+ m_flags.Set(eValueIsValid);
+ else
+ m_flags.Clear(eValueIsValid);
+}
+
+bool
+ValueObject::GetValueDidChange () const
+{
+ return m_flags.IsSet(eValueChanged);
+}
+
+void
+ValueObject::SetValueDidChange (bool value_changed)
+{
+ m_flags.Set(eValueChanged);
+}
+
+ValueObjectSP
+ValueObject::GetChildAtIndex (uint32_t idx, bool can_create)
+{
+ ValueObjectSP child_sp;
+ if (idx < GetNumChildren())
+ {
+ // Check if we have already made the child value object?
+ if (can_create && m_children[idx].get() == NULL)
+ {
+ // 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[idx] = CreateChildAtIndex (idx, false, 0);
+ }
+
+ child_sp = m_children[idx];
+ }
+ return child_sp;
+}
+
+uint32_t
+ValueObject::GetIndexOfChildWithName (const ConstString &name)
+{
+ bool omit_empty_base_classes = true;
+ return ClangASTContext::GetIndexOfChildWithName (GetClangAST(),
+ GetOpaqueClangQualType(),
+ name.AsCString(),
+ omit_empty_base_classes);
+}
+
+ValueObjectSP
+ValueObject::GetChildMemberWithName (const ConstString &name, bool can_create)
+{
+ // when getting a child by name, it could be burried 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
+ std::vector<uint32_t> child_indexes;
+ clang::ASTContext *clang_ast = GetClangAST();
+ void *clang_type = GetOpaqueClangQualType();
+ bool omit_empty_base_classes = true;
+ const size_t num_child_indexes = ClangASTContext::GetIndexOfChildMemberWithName (clang_ast,
+ clang_type,
+ name.AsCString(),
+ omit_empty_base_classes,
+ child_indexes);
+ ValueObjectSP child_sp;
+ 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;
+}
+
+
+uint32_t
+ValueObject::GetNumChildren ()
+{
+ if (m_flags.IsClear(eNumChildrenHasBeenSet))
+ {
+ SetNumChildren (CalculateNumChildren());
+ }
+ return m_children.size();
+}
+void
+ValueObject::SetNumChildren (uint32_t num_children)
+{
+ m_flags.Set(eNumChildrenHasBeenSet);
+ m_children.resize(num_children);
+}
+
+void
+ValueObject::SetName (const char *name)
+{
+ m_name.SetCString(name);
+}
+
+void
+ValueObject::SetName (const ConstString &name)
+{
+ m_name = name;
+}
+
+ValueObjectSP
+ValueObject::CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ ValueObjectSP valobj_sp;
+ bool omit_empty_base_classes = true;
+
+ 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;
+ const bool transparent_pointers = synthetic_array_member == false;
+ clang::ASTContext *clang_ast = GetClangAST();
+ void *clang_type = GetOpaqueClangQualType();
+ void *child_clang_type;
+ child_clang_type = ClangASTContext::GetChildClangTypeAtIndex (clang_ast,
+ GetName().AsCString(),
+ clang_type,
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ child_name_str,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset);
+ 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_sp.reset (new ValueObjectChild (this,
+ clang_ast,
+ child_clang_type,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset));
+ }
+ return valobj_sp;
+}
+
+const char *
+ValueObject::GetSummaryAsCString (ExecutionContextScope *exe_scope)
+{
+ if (UpdateValueIfNeeded (exe_scope))
+ {
+ if (m_summary_str.empty())
+ {
+ void *clang_type = GetOpaqueClangQualType();
+
+ // See if this is a pointer to a C string?
+ uint32_t fixed_length = 0;
+ if (clang_type && ClangASTContext::IsCStringType (clang_type, fixed_length))
+ {
+ Process *process = exe_scope->CalculateProcess();
+ if (process != NULL)
+ {
+ StreamString sstr;
+ lldb::addr_t cstr_address = LLDB_INVALID_ADDRESS;
+ lldb::AddressType cstr_address_type = eAddressTypeInvalid;
+ switch (GetValue().GetValueType())
+ {
+ case Value::eValueTypeScalar:
+ cstr_address = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ cstr_address_type = eAddressTypeLoad;
+ break;
+
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeHostAddress:
+ {
+ uint32_t data_offset = 0;
+ cstr_address = m_data.GetPointer(&data_offset);
+ cstr_address_type = m_value.GetValueAddressType();
+ if (cstr_address_type == eAddressTypeInvalid)
+ cstr_address_type = eAddressTypeLoad;
+ }
+ break;
+ }
+
+ if (cstr_address != LLDB_INVALID_ADDRESS)
+ {
+ DataExtractor data;
+ size_t bytes_read = 0;
+ std::vector<char> data_buffer;
+ std::vector<char> cstr_buffer;
+ size_t cstr_length;
+ Error error;
+ if (fixed_length > 0)
+ {
+ data_buffer.resize(fixed_length);
+ // Resize the formatted buffer in case every character
+ // uses the "\xXX" format and one extra byte for a NULL
+ cstr_buffer.resize(data_buffer.size() * 4 + 1);
+ data.SetData (data_buffer.data(), data_buffer.size(), eByteOrderHost);
+ bytes_read = process->ReadMemory (cstr_address, data_buffer.data(), fixed_length, error);
+ if (bytes_read > 0)
+ {
+ sstr << '"';
+ cstr_length = data.Dump (&sstr,
+ 0, // Start offset in "data"
+ eFormatChar, // Print as characters
+ 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
+ sstr << '"';
+ }
+ }
+ else
+ {
+ const size_t k_max_buf_size = 256;
+ data_buffer.resize (k_max_buf_size + 1);
+ // NULL terminate in case we don't get the entire C string
+ data_buffer.back() = '\0';
+ // Make a formatted buffer that can contain take 4
+ // bytes per character in case each byte uses the
+ // "\xXX" format and one extra byte for a NULL
+ cstr_buffer.resize (k_max_buf_size * 4 + 1);
+
+ data.SetData (data_buffer.data(), data_buffer.size(), eByteOrderHost);
+ size_t total_cstr_len = 0;
+ while ((bytes_read = process->ReadMemory (cstr_address, data_buffer.data(), k_max_buf_size, error)) > 0)
+ {
+ size_t len = strlen(data_buffer.data());
+ if (len == 0)
+ break;
+ if (len > bytes_read)
+ len = bytes_read;
+ if (sstr.GetSize() == 0)
+ sstr << '"';
+
+ cstr_length = data.Dump (&sstr,
+ 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
+
+ if (len < k_max_buf_size)
+ break;
+ cstr_address += total_cstr_len;
+ }
+ if (sstr.GetSize() > 0)
+ sstr << '"';
+ }
+
+ if (sstr.GetSize() > 0)
+ m_summary_str.assign (sstr.GetData(), sstr.GetSize());
+ }
+ }
+ }
+ }
+ }
+ if (m_summary_str.empty())
+ return NULL;
+ return m_summary_str.c_str();
+}
+
+
+const char *
+ValueObject::GetValueAsCString (ExecutionContextScope *exe_scope)
+{
+ // If our byte size is zero this is an aggregate type that has children
+ if (ClangASTContext::IsAggregateType (GetOpaqueClangQualType()) == false)
+ {
+ if (UpdateValueIfNeeded(exe_scope))
+ {
+ if (m_value_str.empty())
+ {
+ const Value::ContextType context_type = m_value.GetContextType();
+
+ switch (context_type)
+ {
+ case Value::eContextTypeOpaqueClangQualType:
+ case Value::eContextTypeDCType:
+ case Value::eContextTypeDCVariable:
+ {
+ void *clang_type = GetOpaqueClangQualType ();
+ if (clang_type)
+ {
+ StreamString sstr;
+ lldb::Format format = Type::GetFormat(clang_type);
+ if (Type::DumpTypeValue(&sstr,
+ GetClangAST(), // The clang AST
+ clang_type, // The clang type to display
+ format, // Format to display this type with
+ 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
+ m_value_str.swap(sstr.GetString());
+ else
+ m_value_str.clear();
+ }
+ }
+ break;
+
+ case Value::eContextTypeDCRegisterInfo:
+ {
+ const RegisterInfo *reg_info = m_value.GetRegisterInfo();
+ if (reg_info)
+ {
+ StreamString reg_sstr;
+ m_data.Dump(&reg_sstr, 0, reg_info->format, reg_info->byte_size, 1, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
+ m_value_str.swap(reg_sstr.GetString());
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (m_value_str.empty())
+ return NULL;
+ return m_value_str.c_str();
+}
+
+bool
+ValueObject::SetValueFromCString (ExecutionContextScope *exe_scope, const char *value_str)
+{
+ // Make sure our value is up to date first so that our location and location
+ // type is valid.
+ if (!UpdateValueIfNeeded(exe_scope))
+ return false;
+
+ uint32_t count = 0;
+ lldb::Encoding encoding = Type::GetEncoding (GetOpaqueClangQualType(), count);
+
+ char *end = NULL;
+ size_t byte_size = GetByteSize();
+ switch (encoding)
+ {
+ case eEncodingInvalid:
+ return false;
+
+ case eEncodingUint:
+ if (byte_size > sizeof(unsigned long long))
+ {
+ return false;
+ }
+ else
+ {
+ unsigned long long ull_val = strtoull(value_str, &end, 0);
+ if (end && *end != '\0')
+ return false;
+ m_value = ull_val;
+ // Limit the bytes in our m_data appropriately.
+ m_value.GetScalar().GetData (m_data, byte_size);
+ }
+ break;
+
+ case eEncodingSint:
+ if (byte_size > sizeof(long long))
+ {
+ return false;
+ }
+ else
+ {
+ long long sll_val = strtoll(value_str, &end, 0);
+ if (end && *end != '\0')
+ return false;
+ m_value = sll_val;
+ // Limit the bytes in our m_data appropriately.
+ m_value.GetScalar().GetData (m_data, byte_size);
+ }
+ break;
+
+ case eEncodingIEEE754:
+ {
+ const size_t byte_size = GetByteSize();
+ const off_t byte_offset = GetByteOffset();
+ uint8_t *dst = (uint8_t *)m_data.PeekData(byte_offset, byte_size);
+ if (dst != NULL)
+ {
+ // We are decoding a float into host byte order below, so make
+ // sure m_data knows what it contains.
+ m_data.SetByteOrder(eByteOrderHost);
+ const size_t converted_byte_size = ClangASTContext::ConvertStringToFloatValue (
+ GetClangAST(),
+ GetOpaqueClangQualType(),
+ value_str,
+ dst,
+ byte_size);
+
+ if (converted_byte_size == byte_size)
+ {
+ }
+ }
+ }
+ break;
+
+ case eEncodingVector:
+ return false;
+
+ default:
+ return false;
+ }
+
+ // If we have made it here the value is in m_data and we should write it
+ // out to the target
+ return Write ();
+}
+
+bool
+ValueObject::Write ()
+{
+ // Clear the update ID so the next time we try and read the value
+ // we try and read it again.
+ m_update_id = 0;
+
+ // TODO: when Value has a method to write a value back, call it from here.
+ return false;
+
+}
+
+void
+ValueObject::AddSyntheticChild (const ConstString &key, ValueObjectSP& valobj_sp)
+{
+ m_synthetic_children[key] = valobj_sp;
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticChild (const ConstString &key) const
+{
+ ValueObjectSP synthetic_child_sp;
+ std::map<ConstString, ValueObjectSP>::const_iterator pos = m_synthetic_children.find (key);
+ if (pos != m_synthetic_children.end())
+ synthetic_child_sp = pos->second;
+ return synthetic_child_sp;
+}
+
+bool
+ValueObject::IsPointerType ()
+{
+ return ClangASTContext::IsPointerType (GetOpaqueClangQualType());
+}
+
+bool
+ValueObject::IsPointerOrReferenceType ()
+{
+ return ClangASTContext::IsPointerOrReferenceType(GetOpaqueClangQualType());
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticArrayMemberFromPointer (int32_t index, bool can_create)
+{
+ ValueObjectSP synthetic_child_sp;
+ if (IsPointerType ())
+ {
+ char index_str[64];
+ snprintf(index_str, sizeof(index_str), "[%i]", 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)
+ {
+ // We haven't made a synthetic array member for INDEX yet, so
+ // lets make one and cache it for any future reference.
+ synthetic_child_sp = CreateChildAtIndex(0, true, index);
+
+ // Cache the value if we got one back...
+ if (synthetic_child_sp)
+ AddSyntheticChild(index_const_str, synthetic_child_sp);
+ }
+ }
+ return synthetic_child_sp;
+}
diff --git a/lldb/source/Core/ValueObjectChild.cpp b/lldb/source/Core/ValueObjectChild.cpp
new file mode 100644
index 00000000000..dc10bb09b4c
--- /dev/null
+++ b/lldb/source/Core/ValueObjectChild.cpp
@@ -0,0 +1,207 @@
+//===-- 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/dwarf.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.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,
+ clang::ASTContext *clang_ast,
+ void *clang_type,
+ const ConstString &name,
+ uint32_t byte_size,
+ int32_t byte_offset,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset
+) :
+ ValueObject (),
+ m_parent (parent),
+ m_clang_ast (clang_ast),
+ 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_name = name;
+}
+
+ValueObjectChild::~ValueObjectChild()
+{
+}
+
+void *
+ValueObjectChild::GetOpaqueClangQualType()
+{
+ return m_clang_type;
+}
+
+lldb::ValueType
+ValueObjectChild::GetValueType() const
+{
+ return m_parent->GetValueType();
+}
+
+uint32_t
+ValueObjectChild::CalculateNumChildren()
+{
+ return ClangASTContext::GetNumChildren (m_clang_type, true);
+}
+
+clang::ASTContext *
+ValueObjectChild::GetClangAST ()
+{
+ return m_clang_ast;
+}
+
+size_t
+ValueObjectChild::GetByteSize()
+{
+ return m_byte_size;
+}
+
+off_t
+ValueObjectChild::GetByteOffset()
+{
+ return m_byte_offset;
+}
+
+uint32_t
+ValueObjectChild::GetBitfieldBitSize()
+{
+ return m_bitfield_bit_size;
+}
+
+uint32_t
+ValueObjectChild::GetBitfieldBitOffset()
+{
+ return m_bitfield_bit_offset;
+}
+
+ConstString
+ValueObjectChild::GetTypeName()
+{
+ if (m_type_name.IsEmpty())
+ {
+ m_type_name = Type::GetClangTypeName (GetOpaqueClangQualType());
+ if (m_type_name)
+ {
+ if (m_bitfield_bit_size > 0)
+ {
+ const char *clang_type_name = m_type_name.AsCString();
+ if (clang_type_name)
+ {
+ char bitfield_type_name[strlen(clang_type_name) + 32];
+ ::snprintf (bitfield_type_name, sizeof(bitfield_type_name), "%s:%u", clang_type_name, m_bitfield_bit_size);
+ m_type_name.SetCString(bitfield_type_name);
+ }
+ }
+ }
+ }
+ return m_type_name;
+}
+
+void
+ValueObjectChild::UpdateValue (ExecutionContextScope *exe_scope)
+{
+ m_error.Clear();
+ SetValueIsValid (false);
+ ValueObject* parent = m_parent;
+ if (parent)
+ {
+ if (parent->UpdateValueIfNeeded(exe_scope))
+ {
+ m_value.SetContext(Value::eContextTypeOpaqueClangQualType, m_clang_type);
+
+ // 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 (ClangASTContext::IsPointerOrReferenceType (parent->GetOpaqueClangQualType()))
+ {
+ uint32_t offset = 0;
+ m_value.GetScalar() = parent->GetDataExtractor().GetPointer(&offset);
+ // For pointers, m_byte_offset should only ever be set if we
+ // ValueObject::GetSyntheticArrayMemberFromPointer() was called
+ if (ClangASTContext::IsPointerType (parent->GetOpaqueClangQualType()) && m_byte_offset)
+ m_value.GetScalar() += m_byte_offset;
+ if (value_type == Value::eValueTypeScalar ||
+ value_type == Value::eValueTypeFileAddress)
+ m_value.SetValueType (Value::eValueTypeLoadAddress);
+ }
+ 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 || addr == 0)
+ {
+ m_error.SetErrorStringWithFormat("Parent address is invalid: 0x%llx.\n", addr);
+ break;
+ }
+ // Set this object's scalar value to the address of its
+ // value be 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 (exe_scope);
+ m_error = m_value.GetValueAsData (&exe_ctx, GetClangAST (), m_data, 0);
+ }
+ }
+ else
+ {
+ m_error.SetErrorStringWithFormat("Parent failed to evaluate: %s.\n", parent->GetError().AsCString());
+ }
+ }
+ else
+ {
+ m_error.SetErrorString("ValueObjectChild has a NULL parent ValueObject.");
+ }
+}
+
+
+bool
+ValueObjectChild::IsInScope (StackFrame *frame)
+{
+ return m_parent->IsInScope (frame);
+}
+
diff --git a/lldb/source/Core/ValueObjectList.cpp b/lldb/source/Core/ValueObjectList.cpp
new file mode 100644
index 00000000000..50ae1de0985
--- /dev/null
+++ b/lldb/source/Core/ValueObjectList.cpp
@@ -0,0 +1,119 @@
+//===-- 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);
+}
+
+uint32_t
+ValueObjectList::GetSize() const
+{
+ return m_value_objects.size();
+}
+
+lldb::ValueObjectSP
+ValueObjectList::GetValueObjectAtIndex (uint32_t idx)
+{
+ lldb::ValueObjectSP valobj_sp;
+ if (idx < m_value_objects.size())
+ valobj_sp = m_value_objects[idx];
+ return 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)
+ {
+ if ((*pos)->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)
+ {
+ if ((*pos)->GetID() == uid)
+ {
+ valobj_sp = *pos;
+ break;
+ }
+ }
+ return valobj_sp;
+}
+
+
+ValueObjectSP
+ValueObjectList::FindValueObjectByPointer (ValueObject *valobj)
+{
+ ValueObjectSP valobj_sp;
+ collection::iterator pos, end = m_value_objects.end();
+
+ for (pos = m_value_objects.begin(); pos != end; ++pos)
+ {
+ if ((*pos).get() == valobj)
+ {
+ valobj_sp = *pos;
+ break;
+ }
+ }
+ return valobj_sp;
+}
diff --git a/lldb/source/Core/ValueObjectRegister.cpp b/lldb/source/Core/ValueObjectRegister.cpp
new file mode 100644
index 00000000000..aae818eadd6
--- /dev/null
+++ b/lldb/source/Core/ValueObjectRegister.cpp
@@ -0,0 +1,331 @@
+//===-- 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/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 (RegisterContext *reg_ctx) :
+ ValueObject (),
+ m_reg_ctx (reg_ctx)
+{
+ assert (reg_ctx);
+ m_name.SetCString("Registers");
+ SetValueIsValid (true);
+}
+
+ValueObjectRegisterContext::~ValueObjectRegisterContext()
+{
+}
+
+void *
+ValueObjectRegisterContext::GetOpaqueClangQualType ()
+{
+ return NULL;
+}
+
+ConstString
+ValueObjectRegisterContext::GetTypeName()
+{
+ ConstString empty_type_name;
+ return empty_type_name;
+}
+
+uint32_t
+ValueObjectRegisterContext::CalculateNumChildren()
+{
+ return m_reg_ctx->GetRegisterSetCount();
+}
+
+clang::ASTContext *
+ValueObjectRegisterContext::GetClangAST ()
+{
+ return NULL;
+}
+
+size_t
+ValueObjectRegisterContext::GetByteSize()
+{
+ return 0;
+}
+
+void
+ValueObjectRegisterContext::UpdateValue (ExecutionContextScope *exe_scope)
+{
+ m_error.Clear();
+ StackFrame *frame = exe_scope->CalculateStackFrame();
+ if (frame)
+ m_reg_ctx = frame->GetRegisterContext();
+ else
+ m_reg_ctx = NULL;
+
+ SetValueIsValid (m_reg_ctx != NULL);
+}
+
+ValueObjectSP
+ValueObjectRegisterContext::CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ ValueObjectSP valobj_sp;
+
+ const uint32_t num_children = GetNumChildren();
+ if (idx < num_children)
+ valobj_sp.reset (new ValueObjectRegisterSet(m_reg_ctx, idx));
+ return valobj_sp;
+}
+
+
+#pragma mark -
+#pragma mark ValueObjectRegisterSet
+
+ValueObjectRegisterSet::ValueObjectRegisterSet (RegisterContext *reg_ctx, uint32_t reg_set_idx) :
+ ValueObject (),
+ m_reg_ctx (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()
+{
+}
+
+void *
+ValueObjectRegisterSet::GetOpaqueClangQualType ()
+{
+ return NULL;
+}
+
+ConstString
+ValueObjectRegisterSet::GetTypeName()
+{
+ return ConstString();
+}
+
+uint32_t
+ValueObjectRegisterSet::CalculateNumChildren()
+{
+ const RegisterSet *reg_set = m_reg_ctx->GetRegisterSet(m_reg_set_idx);
+ if (reg_set)
+ return reg_set->num_registers;
+ return 0;
+}
+
+clang::ASTContext *
+ValueObjectRegisterSet::GetClangAST ()
+{
+ return NULL;
+}
+
+size_t
+ValueObjectRegisterSet::GetByteSize()
+{
+ return 0;
+}
+
+void
+ValueObjectRegisterSet::UpdateValue (ExecutionContextScope *exe_scope)
+{
+ m_error.Clear();
+ SetValueDidChange (false);
+ StackFrame *frame = exe_scope->CalculateStackFrame();
+ if (frame == NULL)
+ m_reg_ctx = NULL;
+ else
+ {
+ m_reg_ctx = frame->GetRegisterContext ();
+ if (m_reg_ctx)
+ {
+ const RegisterSet *reg_set = m_reg_ctx->GetRegisterSet (m_reg_set_idx);
+ if (reg_set == NULL)
+ m_reg_ctx = NULL;
+ else if (m_reg_set != reg_set)
+ {
+ SetValueDidChange (true);
+ m_name.SetCString(reg_set->name);
+ }
+ }
+ }
+ if (m_reg_ctx)
+ {
+ SetValueIsValid (true);
+ }
+ else
+ {
+ SetValueIsValid (false);
+ m_children.clear();
+ }
+}
+
+
+ValueObjectSP
+ValueObjectRegisterSet::CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ ValueObjectSP valobj_sp;
+ if (m_reg_ctx && m_reg_set)
+ {
+ const uint32_t num_children = GetNumChildren();
+ if (idx < num_children)
+ valobj_sp.reset (new ValueObjectRegister(m_reg_ctx, m_reg_set->registers[idx]));
+ }
+ return valobj_sp;
+}
+
+
+#pragma mark -
+#pragma mark ValueObjectRegister
+
+ValueObjectRegister::ValueObjectRegister (RegisterContext *reg_ctx, uint32_t reg_num) :
+ ValueObject (),
+ m_reg_ctx (reg_ctx),
+ m_reg_info (NULL),
+ m_reg_num (reg_num),
+ m_type_name (),
+ m_clang_type (NULL)
+{
+ assert (reg_ctx);
+ m_reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
+ if (m_reg_info)
+ {
+ if (m_reg_info->name)
+ m_name.SetCString(m_reg_info->name);
+ else if (m_reg_info->alt_name)
+ m_name.SetCString(m_reg_info->alt_name);
+ }
+}
+
+ValueObjectRegister::~ValueObjectRegister()
+{
+}
+
+void *
+ValueObjectRegister::GetOpaqueClangQualType ()
+{
+ if (m_clang_type == NULL && m_reg_info)
+ {
+ Process *process = m_reg_ctx->CalculateProcess ();
+ if (process)
+ {
+ Module *exe_module = process->GetTarget().GetExecutableModule ().get();
+ if (exe_module)
+ {
+ TypeList *type_list = exe_module->GetTypeList();
+ if (type_list)
+ m_clang_type = type_list->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 = Type::GetClangTypeName (GetOpaqueClangQualType());
+ return m_type_name;
+}
+
+uint32_t
+ValueObjectRegister::CalculateNumChildren()
+{
+ return 0;
+}
+
+clang::ASTContext *
+ValueObjectRegister::GetClangAST ()
+{
+ Process *process = m_reg_ctx->CalculateProcess ();
+ if (process)
+ {
+ Module *exe_module = process->GetTarget().GetExecutableModule ().get();
+ if (exe_module)
+ {
+ TypeList *type_list = exe_module->GetTypeList();
+ if (type_list)
+ return type_list->GetClangASTContext().getASTContext();
+ }
+ }
+ return NULL;
+}
+
+size_t
+ValueObjectRegister::GetByteSize()
+{
+ return m_reg_info->byte_size;
+}
+
+void
+ValueObjectRegister::UpdateValue (ExecutionContextScope *exe_scope)
+{
+ m_error.Clear();
+ StackFrame *frame = exe_scope->CalculateStackFrame();
+ if (frame)
+ {
+ m_reg_ctx = frame->GetRegisterContext();
+ if (m_reg_ctx)
+ {
+ const RegisterInfo *reg_info = m_reg_ctx->GetRegisterInfoAtIndex(m_reg_num);
+ if (m_reg_info != reg_info)
+ {
+ m_reg_info = reg_info;
+ if (m_reg_info)
+ {
+ if (m_reg_info->name)
+ m_name.SetCString(m_reg_info->name);
+ else if (m_reg_info->alt_name)
+ m_name.SetCString(m_reg_info->alt_name);
+ }
+ }
+ }
+ }
+ else
+ {
+ m_reg_ctx = NULL;
+ m_reg_info = NULL;
+ }
+
+
+ if (m_reg_ctx && m_reg_info)
+ {
+ if (m_reg_ctx->ReadRegisterBytes (m_reg_num, m_data))
+ {
+ m_value.SetContext(Value::eContextTypeDCRegisterInfo, (void *)m_reg_info);
+ m_value.SetValueType(Value::eValueTypeHostAddress);
+ m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
+ SetValueIsValid (true);
+ return;
+ }
+ }
+ SetValueIsValid (false);
+}
+
+
diff --git a/lldb/source/Core/ValueObjectVariable.cpp b/lldb/source/Core/ValueObjectVariable.cpp
new file mode 100644
index 00000000000..0b94535387f
--- /dev/null
+++ b/lldb/source/Core/ValueObjectVariable.cpp
@@ -0,0 +1,167 @@
+//===-- 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/ValueObjectList.h"
+#include "lldb/Core/Value.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"
+
+#include "clang/AST/Type.h"
+
+
+using namespace lldb_private;
+
+ValueObjectVariable::ValueObjectVariable (lldb::VariableSP &var_sp) :
+ ValueObject(),
+ 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()
+{
+}
+
+void *
+ValueObjectVariable::GetOpaqueClangQualType ()
+{
+ Type *var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetOpaqueClangQualType();
+ return NULL;
+}
+
+ConstString
+ValueObjectVariable::GetTypeName()
+{
+ Type * var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetName();
+ ConstString empty_type_name;
+ return empty_type_name;
+}
+
+uint32_t
+ValueObjectVariable::CalculateNumChildren()
+{
+ Type *var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetNumChildren(true);
+ return 0;
+}
+
+clang::ASTContext *
+ValueObjectVariable::GetClangAST ()
+{
+ return m_variable_sp->GetType()->GetClangAST();
+}
+
+size_t
+ValueObjectVariable::GetByteSize()
+{
+ return m_variable_sp->GetType()->GetByteSize();
+}
+
+lldb::ValueType
+ValueObjectVariable::GetValueType() const
+{
+ if (m_variable_sp)
+ return m_variable_sp->GetScope();
+ return lldb::eValueTypeInvalid;
+}
+
+
+
+void
+ValueObjectVariable::UpdateValue (ExecutionContextScope *exe_scope)
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ Variable *variable = m_variable_sp.get();
+ DWARFExpression &expr = variable->LocationExpression();
+ Value old_value(m_value);
+ ExecutionContext exe_ctx (exe_scope);
+ if (expr.Evaluate (&exe_ctx, GetClangAST(), NULL, m_value, &m_error))
+ {
+ m_value.SetContext(Value::eContextTypeDCVariable, variable);
+
+ 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, GetClangAST(), m_data, 0);
+ 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 (ClangASTContext::IsAggregateType (GetOpaqueClangQualType()))
+ {
+ // 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::eContextTypeDCVariable, variable);
+ m_error = value.GetValueAsData(&exe_ctx, GetClangAST(), m_data, 0);
+ }
+ break;
+ }
+
+ SetValueIsValid (m_error.Success());
+ }
+}
+
+
+
+bool
+ValueObjectVariable::IsInScope (StackFrame *frame)
+{
+ return m_variable_sp->IsInScope (frame);
+}
+
diff --git a/lldb/source/Expression/ClangASTSource.cpp b/lldb/source/Expression/ClangASTSource.cpp
new file mode 100644
index 00000000000..996c20529ac
--- /dev/null
+++ b/lldb/source/Expression/ClangASTSource.cpp
@@ -0,0 +1,101 @@
+/*
+ * ClangASTSource.cpp
+ * lldb
+ *
+ * Created by John McCall on 6/1/10.
+ * Copyright 2010 Apple. All rights reserved.
+ *
+ */
+
+#define NO_RTTI
+
+#include "clang/AST/ASTContext.h"
+#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+
+using namespace clang;
+using namespace lldb_private;
+
+ClangASTSource::~ClangASTSource() {}
+
+void ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer) {
+ // Tell Sema to ask us when looking into the translation unit's decl.
+ Context.getTranslationUnitDecl()->setHasExternalVisibleStorage();
+ Context.getTranslationUnitDecl()->setHasExternalLexicalStorage();
+}
+
+// These are only required for AST source that want to lazily load
+// the declarations (or parts thereof) that they return.
+Decl *ClangASTSource::GetExternalDecl(uint32_t) { return 0; }
+Stmt *ClangASTSource::GetExternalDeclStmt(uint64_t) { return 0; }
+
+// These are also optional, although it might help with ObjC
+// debugging if we have respectable signatures. But a more
+// efficient interface (that didn't require scanning all files
+// for method signatures!) might help.
+Selector ClangASTSource::GetExternalSelector(uint32_t) { return Selector(); }
+uint32_t ClangASTSource::GetNumExternalSelectors() { return 0; }
+
+// The core lookup interface.
+DeclContext::lookup_result ClangASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) {
+ switch (Name.getNameKind()) {
+ // Normal identifiers.
+ case DeclarationName::Identifier:
+ break;
+
+ // Operator names. Not important for now.
+ case DeclarationName::CXXOperatorName:
+ case DeclarationName::CXXLiteralOperatorName:
+ return DeclContext::lookup_result();
+
+ // 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:
+ return SetNoExternalVisibleDeclsForName(DC, Name);
+
+ // These aren't looked up like this.
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ return DeclContext::lookup_result();
+
+ // These aren't possible in the global context.
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ return DeclContext::lookup_result();
+ }
+
+ llvm::SmallVector<NamedDecl*, 4> Decls;
+
+ NameSearchContext NSC(*this, Decls, Name, DC);
+
+ DeclMap.GetDecls(NSC, Name.getAsString().c_str());
+ return SetExternalVisibleDeclsForName(DC, Name, Decls);
+}
+
+// This is used to support iterating through an entire lexical context,
+// which isn't something the debugger should ever need to do.
+bool ClangASTSource::FindExternalLexicalDecls(const DeclContext *DC, llvm::SmallVectorImpl<Decl*> &Decls) {
+ // true is for error, that's good enough for me
+ return true;
+}
+
+clang::ASTContext *NameSearchContext::GetASTContext() {
+ return &ASTSource.Context;
+}
+
+clang::NamedDecl *NameSearchContext::AddVarDecl(void *type) {
+ clang::NamedDecl *Decl = VarDecl::Create(ASTSource.Context,
+ const_cast<DeclContext*>(DC),
+ SourceLocation(),
+ Name.getAsIdentifierInfo(),
+ QualType::getFromOpaquePtr(type),
+ 0,
+ VarDecl::Static,
+ VarDecl::Static);
+ Decls.push_back(Decl);
+
+ return Decl;
+}
diff --git a/lldb/source/Expression/ClangExpression.cpp b/lldb/source/Expression/ClangExpression.cpp
new file mode 100644
index 00000000000..f7742c685c7
--- /dev/null
+++ b/lldb/source/Expression/ClangExpression.cpp
@@ -0,0 +1,633 @@
+//===-- ClangExpression.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>
+
+// Other libraries and framework includes
+#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/ModuleBuilder.h"
+#include "clang/Driver/CC1Options.h"
+#include "clang/Driver/OptTable.h"
+#include "clang/Frontend/CodeGenAction.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/Frontend/VerifyDiagnosticsClient.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/ParseAST.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/ExecutionEngine/JIT.h"
+#include "llvm/Module.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/DynamicLibrary.h"
+#include "llvm/System/Host.h"
+#include "llvm/System/Signals.h"
+#include "llvm/Target/TargetSelect.h"
+
+// Project includes
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangStmtVisitor.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Expression/RecordingMemoryManager.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+
+#define NO_RTTI
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Core/dwarf.h"
+
+
+using namespace lldb_private;
+using namespace clang;
+using namespace llvm;
+
+namespace clang {
+
+class AnalyzerOptions;
+class CodeGenOptions;
+class DependencyOutputOptions;
+class DiagnosticOptions;
+class FrontendOptions;
+class HeaderSearchOptions;
+class LangOptions;
+class PreprocessorOptions;
+class PreprocessorOutputOptions;
+class TargetInfo;
+class TargetOptions;
+
+} // end namespace clang
+
+
+
+//===----------------------------------------------------------------------===//
+// Utility Methods
+//===----------------------------------------------------------------------===//
+
+std::string GetBuiltinIncludePath(const char *Argv0) {
+ llvm::sys::Path P =
+ llvm::sys::Path::GetMainExecutable(Argv0,
+ (void*)(intptr_t) GetBuiltinIncludePath);
+
+ if (!P.isEmpty()) {
+ P.eraseComponent(); // Remove /clang from foo/bin/clang
+ P.eraseComponent(); // Remove /bin from foo/bin
+
+ // Get foo/lib/clang/<version>/include
+ P.appendComponent("lib");
+ P.appendComponent("clang");
+ P.appendComponent(CLANG_VERSION_STRING);
+ P.appendComponent("include");
+ }
+
+ return P.str();
+}
+
+
+//===----------------------------------------------------------------------===//
+// Main driver
+//===----------------------------------------------------------------------===//
+
+void LLVMErrorHandler(void *UserData, const std::string &Message) {
+ Diagnostic &Diags = *static_cast<Diagnostic*>(UserData);
+
+ Diags.Report(diag::err_fe_error_backend) << Message;
+
+ // We cannot recover from llvm errors.
+ exit(1);
+}
+
+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 ASTPrintXML: return new ASTPrintXMLAction();
+ 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 EmitObj: return new EmitObjAction();
+ case FixIt: return new FixItAction();
+ case GeneratePCH: return new GeneratePCHAction();
+ case GeneratePTH: return new GeneratePTHAction();
+ case InheritanceView: return new InheritanceViewAction();
+ case InitOnly: return new InitOnlyAction();
+ case ParseNoop: return new ParseOnlyAction();
+ case ParsePrintCallbacks: return new PrintParseAction();
+ case ParseSyntaxOnly: return new SyntaxOnlyAction();
+
+ case PluginAction: {
+ if (CI.getFrontendOpts().ActionName == "help") {
+ llvm::errs() << "clang -cc1 plugins:\n";
+ for (FrontendPluginRegistry::iterator it =
+ FrontendPluginRegistry::begin(),
+ ie = FrontendPluginRegistry::end();
+ it != ie; ++it)
+ llvm::errs() << " " << it->getName() << " - " << it->getDesc() << "\n";
+ return 0;
+ }
+
+ for (FrontendPluginRegistry::iterator it =
+ FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end();
+ it != ie; ++it) {
+ if (it->getName() == CI.getFrontendOpts().ActionName)
+ return it->instantiate();
+ }
+
+ CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name)
+ << CI.getFrontendOpts().ActionName;
+ return 0;
+ }
+
+ case PrintDeclContext: return new DeclContextPrintAction();
+ 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();
+ }
+}
+
+//----------------------------------------------------------------------
+// ClangExpression constructor
+//----------------------------------------------------------------------
+ClangExpression::ClangExpression(const char *target_triple,
+ ClangExpressionDeclMap *decl_map) :
+ m_target_triple (),
+ m_jit_mm_ptr (NULL),
+ m_code_generator_ptr (NULL),
+ m_decl_map (decl_map)
+{
+ if (target_triple && target_triple[0])
+ m_target_triple = target_triple;
+ else
+ m_target_triple = llvm::sys::getHostTriple();
+}
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ClangExpression::~ClangExpression()
+{
+ if (m_code_generator_ptr && !m_execution_engine.get())
+ delete m_code_generator_ptr;
+}
+
+bool
+ClangExpression::CreateCompilerInstance (bool &IsAST)
+{
+ // Initialize targets first, so that --version shows registered targets.
+ static struct InitializeLLVM {
+ InitializeLLVM() {
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
+ }
+ } InitializeLLVM;
+
+ // 1. Create a new compiler instance.
+ m_clang_ap.reset(new CompilerInstance());
+ m_clang_ap->setLLVMContext(new LLVMContext());
+
+ // 2. Set options.
+
+ // Parse expressions as Objective C++ regardless of context.
+ // Our hook into Clang's lookup mechanism only works in C++.
+ m_clang_ap->getLangOpts().CPlusPlus = true;
+ m_clang_ap->getLangOpts().ObjC1 = true;
+
+ // Disable some warnings.
+ m_clang_ap->getDiagnosticOpts().Warnings.push_back("no-unused-value");
+
+ // Set the target triple.
+ m_clang_ap->getTargetOpts().Triple = m_target_triple;
+
+ // 3. Set up various important bits of infrastructure.
+
+ m_clang_ap->createDiagnostics(0, 0);
+ m_clang_ap->getLangOpts().CPlusPlus = true;
+
+ // Create the target instance.
+ m_clang_ap->setTarget(TargetInfo::CreateTargetInfo(m_clang_ap->getDiagnostics(),
+ m_clang_ap->getTargetOpts()));
+ if (!m_clang_ap->hasTarget())
+ {
+ m_clang_ap.reset();
+ return false;
+ }
+
+ // 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_clang_ap->getTarget().setForcedLangOptions(m_clang_ap->getLangOpts());
+
+ return m_clang_ap.get();
+}
+
+Mutex &
+ClangExpression::GetClangMutex ()
+{
+ static Mutex g_clang_mutex(Mutex::eMutexTypeRecursive); // Control access to the clang compiler
+ return g_clang_mutex;
+}
+
+
+clang::ASTContext *
+ClangExpression::GetASTContext ()
+{
+ CompilerInstance *compiler_instance = GetCompilerInstance();
+ if (compiler_instance)
+ return &compiler_instance->getASTContext();
+ return NULL;
+}
+
+unsigned
+ClangExpression::ParseExpression (const char *expr_text, Stream &stream)
+{
+ // HACK: for now we have to make a function body around our expression
+ // since there is no way to parse a single expression line in LLVM/Clang.
+ std::string func_expr("void ___clang_expr()\n{\n\t");
+ func_expr.append(expr_text);
+ func_expr.append(";\n}");
+ return ParseBareExpression (func_expr, stream);
+
+}
+
+unsigned
+ClangExpression::ParseBareExpression (llvm::StringRef expr_text, Stream &stream)
+{
+ Mutex::Locker locker(GetClangMutex ());
+
+ TextDiagnosticBuffer text_diagnostic_buffer;
+
+ bool IsAST = false;
+ if (!CreateCompilerInstance (IsAST))
+ {
+ stream.Printf("error: couldn't create compiler instance\n");
+ return 1;
+ }
+
+ // This code is matched below by a setClient to NULL.
+ // We cannot return out of this code without doing that.
+ m_clang_ap->getDiagnostics().setClient(&text_diagnostic_buffer);
+ text_diagnostic_buffer.FlushDiagnostics (m_clang_ap->getDiagnostics());
+
+ MemoryBuffer *memory_buffer = MemoryBuffer::getMemBufferCopy(expr_text, __FUNCTION__);
+
+ if (!m_clang_ap->hasSourceManager())
+ m_clang_ap->createSourceManager();
+
+ m_clang_ap->createFileManager();
+ m_clang_ap->createPreprocessor();
+
+ // Build the ASTContext. Most of this we inherit from the
+ // CompilerInstance, but we also want to give the context
+ // an ExternalASTSource.
+ SelectorTable selector_table;
+ std::auto_ptr<Builtin::Context> builtin_ap(new Builtin::Context(m_clang_ap->getTarget()));
+ ASTContext *Context = new ASTContext(m_clang_ap->getLangOpts(),
+ m_clang_ap->getSourceManager(),
+ m_clang_ap->getTarget(),
+ m_clang_ap->getPreprocessor().getIdentifierTable(),
+ selector_table,
+ *builtin_ap.get());
+
+ llvm::OwningPtr<ExternalASTSource> ASTSource(new ClangASTSource(*Context, *m_decl_map));
+
+ if (m_decl_map)
+ {
+ Context->setExternalSource(ASTSource);
+ }
+
+ m_clang_ap->setASTContext(Context);
+
+ FileID memory_buffer_file_id = m_clang_ap->getSourceManager().createMainFileIDForMemBuffer (memory_buffer);
+ std::string module_name("test_func");
+ text_diagnostic_buffer.BeginSourceFile(m_clang_ap->getLangOpts(), &m_clang_ap->getPreprocessor());
+
+ if (m_code_generator_ptr)
+ delete m_code_generator_ptr;
+
+ m_code_generator_ptr = CreateLLVMCodeGen(m_clang_ap->getDiagnostics(),
+ module_name,
+ m_clang_ap->getCodeGenOpts(),
+ m_clang_ap->getLLVMContext());
+
+
+ // - CodeGeneration ASTConsumer (include/clang/ModuleBuilder.h), which will be passed in when you call...
+ // - Call clang::ParseAST (in lib/Sema/ParseAST.cpp) to parse the buffer. The CodeGenerator will generate code for __dbg_expr.
+ // - Once ParseAST completes, you can grab the llvm::Module from the CodeGenerator, which will have an llvm::Function you can hand off to the JIT.
+ ParseAST(m_clang_ap->getPreprocessor(), m_code_generator_ptr, m_clang_ap->getASTContext());
+
+ text_diagnostic_buffer.EndSourceFile();
+
+ //compiler_instance->getASTContext().getTranslationUnitDecl()->dump();
+
+ //if (compiler_instance->getFrontendOpts().ShowStats) {
+ // compiler_instance->getFileManager().PrintStats();
+ // fprintf(stderr, "\n");
+ //}
+
+ // This code resolves the setClient above.
+ m_clang_ap->getDiagnostics().setClient(0);
+
+ TextDiagnosticBuffer::const_iterator diag_iterator;
+
+ int num_errors = 0;
+
+#ifdef COUNT_WARNINGS_AND_ERRORS
+ int num_warnings = 0;
+
+ for (diag_iterator = text_diagnostic_buffer.warn_begin();
+ diag_iterator != text_diagnostic_buffer.warn_end();
+ ++diag_iterator)
+ num_warnings++;
+
+ for (diag_iterator = text_diagnostic_buffer.err_begin();
+ diag_iterator != text_diagnostic_buffer.err_end();
+ ++diag_iterator)
+ num_errors++;
+
+ if (num_warnings || num_errors)
+ {
+ if (num_warnings)
+ stream.Printf("%u warning%s%s", num_warnings, (num_warnings == 1 ? "" : "s"), (num_errors ? " and " : ""));
+ if (num_errors)
+ stream.Printf("%u error%s", num_errors, (num_errors == 1 ? "" : "s"));
+ stream.Printf("\n");
+ }
+#endif
+
+ for (diag_iterator = text_diagnostic_buffer.warn_begin();
+ diag_iterator != text_diagnostic_buffer.warn_end();
+ ++diag_iterator)
+ stream.Printf("warning: %s\n", (*diag_iterator).second.c_str());
+
+ num_errors = 0;
+
+ for (diag_iterator = text_diagnostic_buffer.err_begin();
+ diag_iterator != text_diagnostic_buffer.err_end();
+ ++diag_iterator)
+ {
+ num_errors++;
+ stream.Printf("error: %s\n", (*diag_iterator).second.c_str());
+ }
+
+ return num_errors;
+}
+
+
+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[0],
+ CI.getFrontendOpts().ASTMergeFiles.size());
+
+ return Act;
+}
+
+
+unsigned
+ClangExpression::ConvertExpressionToDWARF (ClangExpressionVariableList& expr_local_variable_list,
+ StreamString &dwarf_opcode_strm)
+{
+ CompilerInstance *compiler_instance = GetCompilerInstance();
+
+ DeclarationName hack_func_name(&compiler_instance->getASTContext().Idents.get("___clang_expr"));
+ DeclContext::lookup_result result = compiler_instance->getASTContext().getTranslationUnitDecl()->lookup(hack_func_name);
+
+ if (result.first != result.second)
+ {
+ Decl *decl = *result.first;
+ Stmt *decl_stmt = decl->getBody();
+ if (decl_stmt)
+ {
+ ClangStmtVisitor visitor(compiler_instance->getASTContext(), expr_local_variable_list, m_decl_map, dwarf_opcode_strm);
+
+ visitor.Visit (decl_stmt);
+ }
+ }
+ return 0;
+}
+
+bool
+ClangExpression::JITFunction (const ExecutionContext &exc_context, const char *name)
+{
+
+ llvm::Module *module = m_code_generator_ptr->GetModule();
+
+ if (module)
+ {
+ std::string error;
+
+ if (m_jit_mm_ptr == NULL)
+ m_jit_mm_ptr = new RecordingMemoryManager();
+
+ //llvm::InitializeNativeTarget();
+ if (m_execution_engine.get() == 0)
+ m_execution_engine.reset(llvm::ExecutionEngine::createJIT (module, &error, m_jit_mm_ptr));
+ m_execution_engine->DisableLazyCompilation();
+ llvm::Function *function = module->getFunction (llvm::StringRef (name));
+
+ // We don't actually need the function pointer here, this just forces it to get resolved.
+ void *fun_ptr = m_execution_engine->getPointerToFunction(function);
+ // Note, you probably won't get here on error, since the LLVM JIT tends to just
+ // exit on error at present... So be careful.
+ if (fun_ptr == 0)
+ return false;
+ m_jitted_functions.push_back(ClangExpression::JittedFunction(name, (lldb::addr_t) fun_ptr));
+
+ }
+ return true;
+}
+
+bool
+ClangExpression::WriteJITCode (const ExecutionContext &exc_context)
+{
+ if (m_jit_mm_ptr == NULL)
+ return false;
+
+ if (exc_context.process == NULL)
+ return false;
+
+ // Look over the regions allocated for the function compiled. The JIT
+ // tries to allocate the functions & stubs close together, so we should try to
+ // write them that way too...
+ // For now I only write functions with no stubs, globals, exception tables,
+ // etc. So I only need to write the functions.
+
+ size_t size = 0;
+ std::map<uint8_t *, uint8_t *>::iterator fun_pos, fun_end = m_jit_mm_ptr->m_functions.end();
+ for (fun_pos = m_jit_mm_ptr->m_functions.begin(); fun_pos != fun_end; fun_pos++)
+ {
+ size += (*fun_pos).second - (*fun_pos).first;
+ }
+
+ Error error;
+ lldb::addr_t target_addr = exc_context.process->AllocateMemory (size, lldb::ePermissionsReadable|lldb::ePermissionsExecutable, error);
+
+ if (target_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ lldb::addr_t cursor = target_addr;
+ for (fun_pos = m_jit_mm_ptr->m_functions.begin(); fun_pos != fun_end; fun_pos++)
+ {
+ lldb::addr_t lstart = (lldb::addr_t) (*fun_pos).first;
+ lldb::addr_t lend = (lldb::addr_t) (*fun_pos).second;
+ size_t size = lend - lstart;
+ exc_context.process->WriteMemory(cursor, (void *) lstart, size, error);
+ m_jit_mm_ptr->AddToLocalToRemoteMap (lstart, size, cursor);
+ cursor += size;
+ }
+
+ std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end();
+
+ for (pos = m_jitted_functions.begin(); pos != end; pos++)
+ {
+ (*pos).m_remote_addr = m_jit_mm_ptr->GetRemoteAddressForLocal ((*pos).m_local_addr);
+ }
+ return true;
+}
+
+lldb::addr_t
+ClangExpression::GetFunctionAddress (const char *name)
+{
+ std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end();
+
+ for (pos = m_jitted_functions.begin(); pos < end; pos++)
+ {
+ if (strcmp ((*pos).m_name.c_str(), name) == 0)
+ return (*pos).m_remote_addr;
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+unsigned
+ClangExpression::Compile()
+{
+ Mutex::Locker locker(GetClangMutex ());
+ bool IsAST = false;
+
+ if (CreateCompilerInstance(IsAST))
+ {
+ // Validate/process some options
+ if (m_clang_ap->getHeaderSearchOpts().Verbose)
+ llvm::errs() << "clang-cc version " CLANG_VERSION_STRING
+ << " based upon " << PACKAGE_STRING
+ << " hosted on " << llvm::sys::getHostTriple() << "\n";
+
+ // Enforce certain implications.
+ if (!m_clang_ap->getFrontendOpts().ViewClassInheritance.empty())
+ m_clang_ap->getFrontendOpts().ProgramAction = frontend::InheritanceView;
+// if (!compiler_instance->getFrontendOpts().FixItSuffix.empty())
+// compiler_instance->getFrontendOpts().ProgramAction = frontend::FixIt;
+
+ for (unsigned i = 0, e = m_clang_ap->getFrontendOpts().Inputs.size(); i != e; ++i) {
+ const std::string &InFile = m_clang_ap->getFrontendOpts().Inputs[i].second;
+
+ // If we aren't using an AST file, setup the file and source managers and
+ // the preprocessor.
+ if (!IsAST) {
+ if (!i) {
+ // Create a file manager object to provide access to and cache the
+ // filesystem.
+ m_clang_ap->createFileManager();
+
+ // Create the source manager.
+ m_clang_ap->createSourceManager();
+ } else {
+ // Reset the ID tables if we are reusing the SourceManager.
+ m_clang_ap->getSourceManager().clearIDTables();
+ }
+
+ // Create the preprocessor.
+ m_clang_ap->createPreprocessor();
+ }
+
+ llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(*m_clang_ap.get()));
+ if (!Act)
+ break;
+
+ if (Act->BeginSourceFile(*m_clang_ap, InFile, IsAST)) {
+ Act->Execute();
+ Act->EndSourceFile();
+ }
+ }
+
+ if (m_clang_ap->getDiagnosticOpts().ShowCarets)
+ {
+ unsigned NumWarnings = m_clang_ap->getDiagnostics().getNumWarnings();
+ unsigned NumErrors = m_clang_ap->getDiagnostics().getNumErrors() -
+ m_clang_ap->getDiagnostics().getNumErrorsSuppressed();
+
+ if (NumWarnings || NumErrors)
+ {
+ if (NumWarnings)
+ fprintf (stderr, "%u warning%s%s", NumWarnings, (NumWarnings == 1 ? "" : "s"), (NumErrors ? " and " : ""));
+ if (NumErrors)
+ fprintf (stderr, "%u error%s", NumErrors, (NumErrors == 1 ? "" : "s"));
+ fprintf (stderr, " generated.\n");
+ }
+ }
+
+ if (m_clang_ap->getFrontendOpts().ShowStats) {
+ m_clang_ap->getFileManager().PrintStats();
+ fprintf(stderr, "\n");
+ }
+
+ // Return the appropriate status when verifying diagnostics.
+ //
+ // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need
+ // this.
+ if (m_clang_ap->getDiagnosticOpts().VerifyDiagnostics)
+ return static_cast<VerifyDiagnosticsClient&>(m_clang_ap->getDiagnosticClient()).HadErrors();
+
+ return m_clang_ap->getDiagnostics().getNumErrors();
+ }
+ return 1;
+}
diff --git a/lldb/source/Expression/ClangExpressionDeclMap.cpp b/lldb/source/Expression/ClangExpressionDeclMap.cpp
new file mode 100644
index 00000000000..1065211e45b
--- /dev/null
+++ b/lldb/source/Expression/ClangExpressionDeclMap.cpp
@@ -0,0 +1,246 @@
+//===-- 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 "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/ExecutionContext.h"
+
+//#define DEBUG_CEDM
+#ifdef DEBUG_CEDM
+#define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(...)
+#endif
+
+using namespace lldb_private;
+using namespace clang;
+
+ClangExpressionDeclMap::ClangExpressionDeclMap(ExecutionContext *exe_ctx) :
+ m_exe_ctx(exe_ctx)
+{
+ if (exe_ctx && exe_ctx->frame)
+ m_sym_ctx = new SymbolContext(exe_ctx->frame->GetSymbolContext(lldb::eSymbolContextEverything));
+ else
+ m_sym_ctx = NULL;
+}
+
+ClangExpressionDeclMap::~ClangExpressionDeclMap()
+{
+ uint32_t num_tuples = m_tuples.size ();
+ uint32_t tuple_index;
+
+ for (tuple_index = 0; tuple_index < num_tuples; ++tuple_index)
+ delete m_tuples[tuple_index].m_value;
+
+ if (m_sym_ctx)
+ delete m_sym_ctx;
+}
+
+bool
+ClangExpressionDeclMap::GetIndexForDecl (uint32_t &index,
+ const clang::Decl *decl)
+{
+ uint32_t num_tuples = m_tuples.size ();
+ uint32_t tuple_index;
+
+ for (tuple_index = 0; tuple_index < num_tuples; ++tuple_index)
+ {
+ if (m_tuples[tuple_index].m_decl == decl)
+ {
+ index = tuple_index;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Interface for DwarfExpression
+Value
+*ClangExpressionDeclMap::GetValueForIndex (uint32_t index)
+{
+ if (index >= m_tuples.size ())
+ return NULL;
+
+ return m_tuples[index].m_value;
+}
+
+// Interface for ClangASTSource
+void
+ClangExpressionDeclMap::GetDecls(NameSearchContext &context,
+ const char *name)
+{
+ DEBUG_PRINTF("Hunting for a definition for %s\n", name);
+
+ // Back out in all cases where we're not fully initialized
+ if (!m_exe_ctx || !m_exe_ctx->frame || !m_sym_ctx)
+ return;
+
+ Function *function = m_sym_ctx->function;
+ Block *block = m_sym_ctx->block;
+
+ if (!function || !block)
+ {
+ DEBUG_PRINTF("function = %p, block = %p\n", function, block);
+ return;
+ }
+
+ BlockList& blocks = function->GetBlocks(true);
+
+ lldb::user_id_t current_block_id = block->GetID();
+
+ ConstString name_cs(name);
+
+ for (current_block_id = block->GetID();
+ current_block_id != Block::InvalidID;
+ current_block_id = blocks.GetParent(current_block_id))
+ {
+ Block *current_block = blocks.GetBlockByID(current_block_id);
+
+ lldb::VariableListSP var_list = current_block->GetVariableList(false, true);
+
+ if (!var_list)
+ continue;
+
+ lldb::VariableSP var = var_list->FindVariable(name_cs);
+
+ if (!var)
+ continue;
+
+ AddOneVariable(context, var.get());
+ return;
+ }
+
+ {
+ CompileUnit *compile_unit = m_sym_ctx->comp_unit;
+
+ if (!compile_unit)
+ {
+ DEBUG_PRINTF("compile_unit = %p\n", compile_unit);
+ return;
+ }
+
+ lldb::VariableListSP var_list = compile_unit->GetVariableList(true);
+
+ if (!var_list)
+ return;
+
+ lldb::VariableSP var = var_list->FindVariable(name_cs);
+
+ if (!var)
+ return;
+
+ AddOneVariable(context, var.get());
+ return;
+ }
+}
+
+void
+ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
+ Variable* var)
+{
+ Type *var_type = var->GetType();
+
+ if (!var_type)
+ {
+ DEBUG_PRINTF("Skipped a definition for %s because it has no type\n", name);
+ return;
+ }
+
+ void *var_opaque_type = var_type->GetOpaqueClangQualType();
+
+ if (!var_opaque_type)
+ {
+ DEBUG_PRINTF("Skipped a definition for %s because it has no Clang type\n", name);
+ return;
+ }
+
+ DWARFExpression &var_location_expr = var->LocationExpression();
+
+ TypeList *type_list = var_type->GetTypeList();
+
+ if (!type_list)
+ {
+ DEBUG_PRINTF("Skipped a definition for %s because the type has no associated type list\n", name);
+ return;
+ }
+
+ clang::ASTContext *exe_ast_ctx = type_list->GetClangASTContext().getASTContext();
+
+ if (!exe_ast_ctx)
+ {
+ DEBUG_PRINTF("There is no AST context for the current execution context\n");
+ return;
+ }
+
+ std::auto_ptr<Value> var_location(new Value);
+
+ Error err;
+
+ if (!var_location_expr.Evaluate(m_exe_ctx, exe_ast_ctx, NULL, *var_location.get(), &err))
+ {
+ DEBUG_PRINTF("Error evaluating the location of %s: %s\n", name, err.AsCString());
+ return;
+ }
+
+ void *copied_type = ClangASTContext::CopyType(context.GetASTContext(), type_list->GetClangASTContext().getASTContext(), var_opaque_type);
+
+ if (var_location.get()->GetContextType() == Value::eContextTypeInvalid)
+ var_location.get()->SetContext(Value::eContextTypeOpaqueClangQualType, copied_type);
+
+ if (var_location.get()->GetValueType() == Value::eValueTypeFileAddress)
+ {
+ SymbolContext var_sc;
+ var->CalculateSymbolContext(&var_sc);
+
+ if (!var_sc.module_sp)
+ return;
+
+ ObjectFile *object_file = var_sc.module_sp->GetObjectFile();
+
+ if (!object_file)
+ return;
+
+ Address so_addr(var_location->GetScalar().ULongLong(), object_file->GetSectionList());
+
+ lldb::addr_t load_addr = so_addr.GetLoadAddress(m_exe_ctx->process);
+
+ var_location->GetScalar() = load_addr;
+ var_location->SetValueType(Value::eValueTypeLoadAddress);
+ }
+
+ NamedDecl *var_decl = context.AddVarDecl(copied_type);
+
+ Tuple tuple;
+
+ tuple.m_decl = var_decl;
+ tuple.m_value = var_location.release();
+
+ m_tuples.push_back(tuple);
+
+ DEBUG_PRINTF("Found for a definition for %s\n", name);
+}
diff --git a/lldb/source/Expression/ClangExpressionVariable.cpp b/lldb/source/Expression/ClangExpressionVariable.cpp
new file mode 100644
index 00000000000..40fee4b47f5
--- /dev/null
+++ b/lldb/source/Expression/ClangExpressionVariable.cpp
@@ -0,0 +1,100 @@
+//===-- 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"
+
+using namespace lldb_private;
+using namespace clang;
+
+ClangExpressionVariableList::ClangExpressionVariableList() :
+ m_variables()
+{
+}
+
+ClangExpressionVariableList::~ClangExpressionVariableList()
+{
+ uint32_t num_variables = m_variables.size();
+ uint32_t var_index;
+
+ for (var_index = 0; var_index < num_variables; ++var_index)
+ delete m_variables[var_index].m_value;
+}
+
+Value *
+ValueForDecl(ASTContext &ast_context, const VarDecl *var_decl)
+{
+ Value *ret = new Value;
+
+ ret->SetContext(Value::eContextTypeOpaqueClangQualType,
+ var_decl->getType().getAsOpaquePtr());
+
+ uint64_t bit_width = ast_context.getTypeSize(var_decl->getType());
+
+ uint32_t byte_size = (bit_width + 7 ) / 8;
+
+ ret->ResizeData(byte_size);
+
+ return ret;
+}
+
+Value *
+ClangExpressionVariableList::GetVariableForVarDecl (ASTContext &ast_context, const VarDecl *var_decl, uint32_t& idx, bool can_create)
+{
+ uint32_t num_variables = m_variables.size();
+ uint32_t var_index;
+
+ for (var_index = 0; var_index < num_variables; ++var_index)
+ {
+ if (m_variables[var_index].m_var_decl == var_decl)
+ {
+ idx = var_index;
+ return m_variables[var_index].m_value;
+ }
+ }
+
+ if (!can_create)
+ return NULL;
+
+ idx = m_variables.size();
+
+ ClangExpressionVariable val;
+ val.m_var_decl = var_decl;
+ val.m_value = ValueForDecl(ast_context, var_decl);
+ m_variables.push_back(val);
+
+ return m_variables.back().m_value;
+}
+
+Value *
+ClangExpressionVariableList::GetVariableAtIndex (uint32_t idx)
+{
+ if (idx < m_variables.size())
+ return m_variables[idx].m_value;
+
+ return NULL;
+}
+
+uint32_t
+ClangExpressionVariableList::AppendValue (Value *value)
+{
+ uint32_t idx = m_variables.size();
+
+ ClangExpressionVariable val;
+ val.m_var_decl = NULL;
+ val.m_value = value;
+
+ m_variables.push_back(val);
+ return idx;
+}
diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp
new file mode 100644
index 00000000000..e8713d0fd49
--- /dev/null
+++ b/lldb/source/Expression/ClangFunction.cpp
@@ -0,0 +1,671 @@
+//===-- 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/Frontend/CodeGenAction.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
+#include "llvm/ExecutionEngine/JIT.h"
+#include "llvm/Module.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "llvm/ADT/StringRef.h"
+
+// Project includes
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Core/DataExtractor.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/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(const char *target_triple, ClangASTContext *ast_context, void *return_qualtype, const Address& functionAddress, const ValueList &arg_value_list) :
+ ClangExpression (target_triple, NULL),
+ m_function_addr (functionAddress),
+ m_function_ptr (NULL),
+ m_arg_values (arg_value_list),
+ m_clang_ast_context (ast_context),
+ m_function_return_qual_type(return_qualtype),
+ m_wrapper_function_name ("__lldb_caller_function"),
+ m_wrapper_struct_name ("__lldb_caller_struct"),
+ m_return_offset(0),
+ m_compiled (false),
+ m_JITted (false)
+{
+}
+
+ClangFunction::ClangFunction(const char *target_triple, Function &function, ClangASTContext *ast_context, const ValueList &arg_value_list) :
+ ClangExpression (target_triple, NULL),
+ m_function_ptr (&function),
+ m_arg_values (arg_value_list),
+ m_clang_ast_context (ast_context),
+ m_function_return_qual_type (NULL),
+ m_wrapper_function_name ("__lldb_function_caller"),
+ m_wrapper_struct_name ("__lldb_caller_struct"),
+ m_return_offset(0),
+ m_compiled (false),
+ m_JITted (false)
+{
+ m_function_addr = m_function_ptr->GetAddressRange().GetBaseAddress();
+ m_function_return_qual_type = m_function_ptr->GetReturnType().GetOpaqueClangQualType();
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ClangFunction::~ClangFunction()
+{
+}
+
+unsigned
+ClangFunction::CompileFunction (Stream &errors)
+{
+ // FIXME: How does clang tell us there's no return value? We need to handle that case.
+ unsigned num_errors = 0;
+
+ if (!m_compiled)
+ {
+ std::string return_type_str = ClangASTContext::GetTypeName(m_function_return_qual_type);
+
+ // 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...
+ std::string expression;
+ expression.append ("extern \"C\" void ");
+ expression.append (m_wrapper_function_name);
+ expression.append (" (void *input)\n{\n struct ");
+ expression.append (m_wrapper_struct_name);
+ expression.append (" \n {\n");
+ expression.append (" ");
+ expression.append (return_type_str);
+ expression.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.
+
+ size_t num_args = -1;
+ bool trust_function = false;
+ // GetArgumentCount returns -1 for an unprototyped function.
+ if (m_function_ptr)
+ {
+ num_args = m_function_ptr->GetArgumentCount();
+ if (num_args != -1)
+ trust_function = true;
+ }
+
+ if (num_args == -1)
+ 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 (int i = 0; i < num_args; i++)
+ {
+ const char *type_string;
+ std::string type_stdstr;
+
+ if (trust_function)
+ {
+ type_string = m_function_ptr->GetArgumentTypeAtIndex(i).GetName().AsCString();
+ }
+ else
+ {
+ Value *arg_value = m_arg_values.GetValueAtIndex(i);
+ void *clang_qual_type = arg_value->GetOpaqueClangQualType ();
+ if (clang_qual_type != NULL)
+ {
+ type_stdstr = ClangASTContext::GetTypeName(clang_qual_type);
+ type_string = type_stdstr.c_str();
+ }
+ else
+ {
+ errors.Printf("Could not determine type of input value %d.", i);
+ return 1;
+ }
+ }
+
+
+ expression.append (type_string);
+ if (i < num_args - 1)
+ expression.append (", ");
+
+ char arg_buf[32];
+ args_buffer.append (" ");
+ args_buffer.append (type_string);
+ snprintf(arg_buf, 31, "arg_%d", 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 (", ");
+
+ }
+ expression.append (");\n"); // Close off the function calling prototype.
+
+ expression.append (args_buffer);
+
+ expression.append (" ");
+ expression.append (return_type_str);
+ expression.append (" return_value;");
+ expression.append ("\n };\n struct ");
+ expression.append (m_wrapper_struct_name);
+ expression.append ("* __lldb_fn_data = (struct ");
+ expression.append (m_wrapper_struct_name);
+ expression.append (" *) input;\n");
+
+ expression.append (" __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr (");
+ expression.append (args_list_buffer);
+ expression.append (");\n}\n");
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf ("Expression: \n\n%s\n\n", expression.c_str());
+
+ // Okay, now compile this expression:
+ num_errors = ParseBareExpression (expression.c_str(), errors);
+ m_compiled = (num_errors == 0);
+
+ if (m_compiled)
+ {
+ using namespace clang;
+ CompilerInstance *compiler_instance = GetCompilerInstance();
+ ASTContext &ast_context = compiler_instance->getASTContext();
+
+ DeclarationName wrapper_func_name(&ast_context.Idents.get(m_wrapper_function_name.c_str()));
+ FunctionDecl::lookup_result func_lookup = ast_context.getTranslationUnitDecl()->lookup(wrapper_func_name);
+ if (func_lookup.first == func_lookup.second)
+ return false;
+
+ FunctionDecl *wrapper_func = dyn_cast<FunctionDecl> (*(func_lookup.first));
+ if (!wrapper_func)
+ return false;
+
+ DeclarationName wrapper_struct_name(&ast_context.Idents.get(m_wrapper_struct_name.c_str()));
+ RecordDecl::lookup_result struct_lookup = wrapper_func->lookup(wrapper_struct_name);
+ if (struct_lookup.first == struct_lookup.second)
+ return false;
+
+ RecordDecl *wrapper_struct = dyn_cast<RecordDecl>(*(struct_lookup.first));
+
+ if (!wrapper_struct)
+ return false;
+
+ m_struct_layout = &ast_context.getASTRecordLayout (wrapper_struct);
+ if (!m_struct_layout)
+ {
+ m_compiled = false;
+ return 1;
+ }
+ m_return_offset = m_struct_layout->getFieldOffset(m_struct_layout->getFieldCount() - 1);
+ m_return_size = (m_struct_layout->getDataSize() - m_return_offset)/8;
+ }
+ }
+
+ return num_errors;
+}
+
+bool
+ClangFunction::WriteFunctionWrapper (ExecutionContext &exc_context, Stream &errors)
+{
+ Process *process = exc_context.process;
+
+ if (process == NULL)
+ return false;
+
+ if (!m_JITted)
+ {
+ // Next we should JIT it and insert the result into the target program.
+ if (!JITFunction (exc_context, m_wrapper_function_name.c_str()))
+ return false;
+
+ if (!WriteJITCode (exc_context))
+ return false;
+
+ m_JITted = true;
+ }
+
+ // Next get the call address for the function:
+ m_wrapper_fun_addr = GetFunctionAddress (m_wrapper_function_name.c_str());
+ if (m_wrapper_fun_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ return true;
+}
+
+bool
+ClangFunction::WriteFunctionArguments (ExecutionContext &exc_context, lldb::addr_t &args_addr_ref, Stream &errors)
+{
+ return WriteFunctionArguments(exc_context, 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 &exc_context, lldb::addr_t &args_addr_ref, Address function_address, ValueList &arg_values, Stream &errors)
+{
+ // Otherwise, allocate space for the argument passing struct, and write it.
+ // We use the information in the expression parser AST to
+ // figure out how to do this...
+ // We should probably transcode this in this object so we can ditch the compiler instance
+ // and all its associated data, and just keep the JITTed bytes.
+
+ Error error;
+ using namespace clang;
+ ExecutionResults return_value = eExecutionSetupError;
+
+ Process *process = exc_context.process;
+
+ if (process == NULL)
+ return return_value;
+
+ uint64_t struct_size = m_struct_layout->getSize()/8; // Clang returns sizes in bytes.
+
+ if (args_addr_ref == LLDB_INVALID_ADDRESS)
+ {
+ args_addr_ref = process->AllocateMemory(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;
+ }
+ }
+
+ // FIXME: This is fake, and just assumes that it matches that architecture.
+ // Make a data extractor and put the address into the right byte order & size.
+
+ uint64_t fun_addr = function_address.GetLoadAddress(exc_context.process);
+ int first_offset = m_struct_layout->getFieldOffset(0)/8;
+ process->WriteMemory(args_addr_ref + first_offset, &fun_addr, 8, 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: %d should be: %d", num_args, m_arg_values.GetSize());
+ return false;
+ }
+
+ for (int i = 0; i < num_args; i++)
+ {
+ // FIXME: We should sanity check sizes.
+
+ int offset = m_struct_layout->getFieldOffset(i+1)/8; // 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::eContextTypeOpaqueClangQualType &&
+ ClangASTContext::IsPointerType(arg_value->GetValueOpaqueClangQualType()))
+ continue;
+
+ const Scalar &arg_scalar = arg_value->ResolveValue(&exc_context, m_clang_ast_context->getASTContext());
+
+ int byte_size = arg_scalar.GetByteSize();
+ std::vector<uint8_t> buffer;
+ buffer.resize(byte_size);
+ DataExtractor value_data;
+ arg_scalar.GetData (value_data);
+ value_data.ExtractBytes(0, byte_size, process->GetByteOrder(), buffer.data());
+ process->WriteMemory(args_addr_ref + offset, buffer.data(), byte_size, error);
+ }
+
+ return true;
+}
+
+bool
+ClangFunction::InsertFunction (ExecutionContext &exc_context, lldb::addr_t &args_addr_ref, Stream &errors)
+{
+ using namespace clang;
+
+ if (CompileFunction(errors) != 0)
+ return false;
+ if (!WriteFunctionWrapper(exc_context, errors))
+ return false;
+ if (!WriteFunctionArguments(exc_context, args_addr_ref, errors))
+ return false;
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf ("Call Address: 0x%llx Struct Address: 0x%llx.\n", m_wrapper_fun_addr, args_addr_ref);
+
+ return true;
+}
+
+ThreadPlan *
+ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exc_context, lldb::addr_t &args_addr, Stream &errors, bool stop_others, bool discard_on_error)
+{
+ // FIXME: Use the errors Stream for better error reporting.
+
+ Process *process = exc_context.process;
+
+ if (process == NULL)
+ {
+ errors.Printf("Can't call a function without a process.");
+ return NULL;
+ }
+
+ // Okay, now run the function:
+
+ Address wrapper_address (NULL, m_wrapper_fun_addr);
+ ThreadPlan *new_plan = new ThreadPlanCallFunction (*exc_context.thread,
+ wrapper_address,
+ args_addr,
+ stop_others, discard_on_error);
+ return new_plan;
+}
+
+bool
+ClangFunction::FetchFunctionResults (ExecutionContext &exc_context, 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.
+
+ std::vector<uint8_t> data_buffer;
+ data_buffer.resize(m_return_size);
+ Process *process = exc_context.process;
+ Error error;
+ size_t bytes_read = process->ReadMemory(args_addr + m_return_offset/8, data_buffer.data(), m_return_size, error);
+
+ if (bytes_read == 0)
+ {
+ return false;
+ }
+
+ if (bytes_read < m_return_size)
+ return false;
+
+ DataExtractor data(data_buffer.data(), m_return_size, process->GetByteOrder(), process->GetAddressByteSize());
+ // FIXME: Assuming an integer scalar for now:
+
+ uint32_t offset = 0;
+ uint64_t return_integer = data.GetMaxU64(&offset, m_return_size);
+
+ ret_value.SetContext (Value::eContextTypeOpaqueClangQualType, m_function_return_qual_type);
+ ret_value.SetValueType(Value::eValueTypeScalar);
+ ret_value.GetScalar() = return_integer;
+ return true;
+}
+
+void
+ClangFunction::DeallocateFunctionResults (ExecutionContext &exc_context, 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);
+
+ exc_context.process->DeallocateMemory(args_addr);
+}
+
+ClangFunction::ExecutionResults
+ClangFunction::ExecuteFunction(ExecutionContext &exc_context, Stream &errors, Value &results)
+{
+ return ExecuteFunction (exc_context, errors, 1000, true, results);
+}
+
+ClangFunction::ExecutionResults
+ClangFunction::ExecuteFunction(ExecutionContext &exc_context, Stream &errors, bool stop_others, Value &results)
+{
+ return ExecuteFunction (exc_context, NULL, errors, stop_others, NULL, false, results);
+}
+
+ClangFunction::ExecutionResults
+ClangFunction::ExecuteFunction(
+ ExecutionContext &exc_context,
+ Stream &errors,
+ uint32_t single_thread_timeout_usec,
+ bool try_all_threads,
+ Value &results)
+{
+ return ExecuteFunction (exc_context, NULL, errors, true, single_thread_timeout_usec, try_all_threads, results);
+}
+
+ClangFunction::ExecutionResults
+ClangFunction::ExecuteFunction(
+ ExecutionContext &exc_context,
+ lldb::addr_t *args_addr_ptr,
+ Stream &errors,
+ bool stop_others,
+ uint32_t single_thread_timeout_usec,
+ bool try_all_threads,
+ Value &results)
+{
+ using namespace clang;
+ ExecutionResults return_value = eExecutionSetupError;
+ Process *process = exc_context.process;
+
+ 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(exc_context, args_addr, errors))
+ return eExecutionSetupError;
+ }
+
+
+ lldb::ThreadPlanSP call_plan_sp(GetThreadPlanToCallFunction(exc_context, args_addr, errors, stop_others, false));
+
+ ThreadPlanCallFunction *call_plan_ptr = static_cast<ThreadPlanCallFunction *> (call_plan_sp.get());
+
+ if (args_addr_ptr != NULL)
+ *args_addr_ptr = args_addr;
+
+ if (call_plan_sp == NULL)
+ return return_value;
+
+ call_plan_sp->SetPrivate(true);
+ exc_context.thread->QueueThreadPlan(call_plan_sp, true);
+
+ // 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.
+
+ TimeValue* timeout_ptr = NULL;
+ TimeValue real_timeout;
+ if (single_thread_timeout_usec != 0)
+ {
+ real_timeout = TimeValue::Now();
+ real_timeout.OffsetWithMicroSeconds(single_thread_timeout_usec);
+ timeout_ptr = &real_timeout;
+ }
+ process->Resume ();
+
+
+ while (1)
+ {
+ lldb::EventSP event_sp;
+
+ // Now wait for the process to stop again:
+ // FIXME: Probably want a time out.
+ lldb::StateType stop_state = process->WaitForStateChangedEvents (timeout_ptr, event_sp);
+ if (stop_state == lldb::eStateInvalid && timeout_ptr != NULL)
+ {
+ // Right now this is the only way to tell we've timed out...
+ // We should interrupt the process here...
+ // Not really sure what to do if Halt fails here...
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf ("Running function with timeout: %d timed out, trying with all threads enabled.", single_thread_timeout_usec);
+
+ if (process->Halt().Success())
+ {
+ timeout_ptr = NULL;
+
+ lldb::StateType stop_state = process->WaitForStateChangedEvents (timeout_ptr, event_sp);
+ if (stop_state == lldb::eStateInvalid)
+ {
+ errors.Printf ("Got an invalid stop state after halt.");
+ }
+ else if (stop_state != lldb::eStateStopped)
+ {
+ StreamString s;
+ event_sp->Dump (&s);
+
+ errors.Printf("Didn't get a stopped event after Halting the target, got: \"%s\"", s.GetData());
+ }
+
+ if (try_all_threads)
+ {
+ // Between the time that we got the timeout and the time we halted, but target
+ // might have actually completed the plan. If so, we're done.
+ if (exc_context.thread->IsThreadPlanDone (call_plan_sp.get()))
+ {
+ return_value = eExecutionCompleted;
+ break;
+ }
+
+
+ call_plan_ptr->SetStopOthers (false);
+ process->Resume();
+ continue;
+ }
+ else
+ return eExecutionInterrupted;
+ }
+ }
+ if (stop_state == lldb::eStateRunning || stop_state == lldb::eStateStepping)
+ continue;
+
+ if (exc_context.thread->IsThreadPlanDone (call_plan_sp.get()))
+ {
+ return_value = eExecutionCompleted;
+ break;
+ }
+ else if (exc_context.thread->WasThreadPlanDiscarded (call_plan_sp.get()))
+ {
+ return_value = eExecutionDiscarded;
+ break;
+ }
+ else
+ {
+ return_value = eExecutionInterrupted;
+ break;
+ }
+
+ }
+
+ if (return_value != eExecutionCompleted)
+ return return_value;
+
+ FetchFunctionResults(exc_context, args_addr, results);
+
+ if (args_addr_ptr == NULL)
+ DeallocateFunctionResults(exc_context, args_addr);
+
+ return eExecutionCompleted;
+}
+
+ClangFunction::ExecutionResults
+ClangFunction::ExecuteFunctionWithABI(ExecutionContext &exc_context, Stream &errors, Value &results)
+{
+ // FIXME: Use the errors Stream for better error reporting.
+ using namespace clang;
+ ExecutionResults return_value = eExecutionSetupError;
+
+ Process *process = exc_context.process;
+
+ if (process == NULL)
+ {
+ errors.Printf("Can't call a function without a process.");
+ return return_value;
+ }
+
+ //unsigned int num_args = m_arg_values.GetSize();
+ //unsigned int arg_index;
+
+ //for (arg_index = 0; arg_index < num_args; ++arg_index)
+ // m_arg_values.GetValueAtIndex(arg_index)->ResolveValue(&exc_context, GetASTContext());
+
+ ThreadPlan *call_plan = exc_context.thread->QueueThreadPlanForCallFunction (false,
+ m_function_addr,
+ m_arg_values,
+ true);
+ if (call_plan == NULL)
+ return return_value;
+
+ call_plan->SetPrivate(true);
+
+ // 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.
+
+ process->Resume ();
+
+ while (1)
+ {
+ lldb::EventSP event_sp;
+
+ // Now wait for the process to stop again:
+ // FIXME: Probably want a time out.
+ lldb::StateType stop_state = process->WaitForStateChangedEvents (NULL, event_sp);
+ if (stop_state == lldb::eStateRunning || stop_state == lldb::eStateStepping)
+ continue;
+
+ if (exc_context.thread->IsThreadPlanDone (call_plan))
+ {
+ return_value = eExecutionCompleted;
+ break;
+ }
+ else if (exc_context.thread->WasThreadPlanDiscarded (call_plan))
+ {
+ return_value = eExecutionDiscarded;
+ break;
+ }
+ else
+ {
+ return_value = eExecutionInterrupted;
+ break;
+ }
+
+ }
+
+ return eExecutionCompleted;
+}
diff --git a/lldb/source/Expression/ClangStmtVisitor.cpp b/lldb/source/Expression/ClangStmtVisitor.cpp
new file mode 100644
index 00000000000..1d2f53fcb80
--- /dev/null
+++ b/lldb/source/Expression/ClangStmtVisitor.cpp
@@ -0,0 +1,1032 @@
+//===-- ClangStmtVisitor.cpp ------------------------------------*- 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/ClangStmtVisitor.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "clang/AST/RecordLayout.h"
+
+#define NO_RTTI
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+
+//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
+#ifdef ENABLE_DEBUG_PRINTF
+#include <stdio.h>
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+// Project includes
+
+static lldb_private::Scalar::Type
+GetScalarTypeForClangType (clang::ASTContext &ast_context, clang::QualType clang_type, uint32_t &count)
+{
+ count = 1;
+
+ switch (clang_type->getTypeClass())
+ {
+ 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<clang::BuiltinType>(clang_type)->getKind())
+ {
+ default: assert(0 && "Unknown builtin type!");
+ case clang::BuiltinType::Void:
+ break;
+
+ case clang::BuiltinType::Bool:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::Int128:
+ return lldb_private::Scalar::GetValueTypeForSignedIntegerWithByteSize ((ast_context.getTypeSize(clang_type)/CHAR_BIT)/count);
+
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::UInt128:
+ case clang::BuiltinType::NullPtr:
+ return lldb_private::Scalar::GetValueTypeForUnsignedIntegerWithByteSize ((ast_context.getTypeSize(clang_type)/CHAR_BIT)/count);
+
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::LongDouble:
+ return lldb_private::Scalar::GetValueTypeForFloatWithByteSize ((ast_context.getTypeSize(clang_type)/CHAR_BIT)/count);
+ }
+ 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_private::Scalar::GetValueTypeForUnsignedIntegerWithByteSize ((ast_context.getTypeSize(clang_type)/CHAR_BIT)/count);
+
+ // Complex numbers are made up of floats
+ case clang::Type::Complex:
+ count = 2;
+ return lldb_private::Scalar::GetValueTypeForFloatWithByteSize ((ast_context.getTypeSize(clang_type)/CHAR_BIT) / count);
+
+ case clang::Type::ObjCInterface: break;
+ case clang::Type::Record: break;
+ case clang::Type::Enum:
+ return lldb_private::Scalar::GetValueTypeForSignedIntegerWithByteSize ((ast_context.getTypeSize(clang_type)/CHAR_BIT)/count);
+
+ case clang::Type::Typedef:
+ return GetScalarTypeForClangType(ast_context, cast<clang::TypedefType>(clang_type)->LookThroughTypedefs(), count);
+ break;
+
+ case clang::Type::TypeOfExpr:
+ case clang::Type::TypeOf:
+ case clang::Type::Decltype:
+ //case clang::Type::QualifiedName:
+ case clang::Type::TemplateSpecialization: break;
+ }
+ count = 0;
+ return lldb_private::Scalar::e_void;
+}
+
+//----------------------------------------------------------------------
+// ClangStmtVisitor constructor
+//----------------------------------------------------------------------
+lldb_private::ClangStmtVisitor::ClangStmtVisitor
+(
+ clang::ASTContext &ast_context,
+ lldb_private::ClangExpressionVariableList &variable_list,
+ lldb_private::ClangExpressionDeclMap *decl_map,
+ lldb_private::StreamString &strm
+) :
+ m_ast_context (ast_context),
+ m_variable_list (variable_list),
+ m_decl_map (decl_map),
+ m_stream (strm)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+lldb_private::ClangStmtVisitor::~ClangStmtVisitor()
+{
+}
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitStmt (clang::Stmt *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+
+ clang::Stmt::child_iterator pos;
+ clang::Stmt::child_iterator begin = Node->child_begin();
+ clang::Stmt::child_iterator end = Node->child_end();
+ bool clear_before_next_stmt = false;
+ for (pos = begin; pos != end; ++pos)
+ {
+#ifdef ENABLE_DEBUG_PRINTF
+ pos->dump();
+#endif
+ clang::Stmt *child_stmt = *pos;
+ uint32_t pre_visit_stream_offset = m_stream.GetSize();
+ bool not_null_stmt = dyn_cast<clang::NullStmt>(child_stmt) == NULL;
+ if (clear_before_next_stmt && not_null_stmt)
+ m_stream.PutHex8(DW_OP_APPLE_clear);
+ Visit (child_stmt);
+ if (not_null_stmt)
+ clear_before_next_stmt = pre_visit_stream_offset != m_stream.GetSize();
+ }
+}
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitDeclStmt (clang::DeclStmt *decl_stmt)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+ clang::DeclGroupRef decl_group_ref = decl_stmt->getDeclGroup();
+ clang::DeclGroupRef::iterator pos, end = decl_group_ref.end();
+ for (pos = decl_group_ref.begin(); pos != end; ++pos)
+ {
+ clang::Decl *decl = *pos;
+ if (decl)
+ {
+ clang::Decl::Kind decl_kind = decl->getKind();
+
+ switch (decl_kind)
+ {
+ case clang::Decl::Namespace:
+ case clang::Decl::Enum:
+ case clang::Decl::Record:
+ case clang::Decl::CXXRecord:
+ case clang::Decl::ObjCMethod:
+ case clang::Decl::ObjCInterface:
+ case clang::Decl::ObjCCategory:
+ case clang::Decl::ObjCProtocol:
+ case clang::Decl::ObjCImplementation:
+ case clang::Decl::ObjCCategoryImpl:
+ case clang::Decl::LinkageSpec:
+ case clang::Decl::Block:
+ case clang::Decl::Function:
+ case clang::Decl::CXXMethod:
+ case clang::Decl::CXXConstructor:
+ case clang::Decl::CXXDestructor:
+ case clang::Decl::CXXConversion:
+ case clang::Decl::Field:
+ case clang::Decl::Typedef:
+ case clang::Decl::EnumConstant:
+ case clang::Decl::ImplicitParam:
+ case clang::Decl::ParmVar:
+ case clang::Decl::ObjCProperty:
+ break;
+
+ case clang::Decl::Var:
+ {
+ const clang::VarDecl *var_decl = cast<clang::VarDecl>(decl)->getCanonicalDecl();
+ uint32_t expr_local_var_idx = UINT32_MAX;
+ if (m_variable_list.GetVariableForVarDecl (m_ast_context, var_decl, expr_local_var_idx, true))
+ {
+ const clang::Expr* var_decl_expr = var_decl->getAnyInitializer();
+ // If there is an inialization expression, then assign the
+ // variable.
+ if (var_decl_expr)
+ {
+ m_stream.PutHex8(DW_OP_APPLE_expr_local);
+ m_stream.PutULEB128(expr_local_var_idx);
+ Visit ((clang::Stmt *)var_decl_expr);
+ m_stream.PutHex8(DW_OP_APPLE_assign);
+ }
+ }
+ }
+ break;
+
+ default:
+ assert(!"decl unhandled");
+ break;
+ }
+ }
+ }
+}
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitLabelStmt (clang::LabelStmt *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitGotoStmt (clang::GotoStmt *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+// Exprs
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitExpr (clang::Expr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitDeclRefExpr (clang::DeclRefExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+ clang::NamedDecl *decl = Node->getDecl();
+ clang::QualType clang_type = Node->getType();
+
+#ifdef ENABLE_DEBUG_PRINTF
+ //decl->dump();
+ //clang_type.dump("lldb_private::ClangStmtVisitor::VisitDeclRefExpr() -> clang_type.dump() = ");
+#endif
+ uint32_t expr_local_var_idx = UINT32_MAX;
+ if (m_variable_list.GetVariableForVarDecl (m_ast_context, cast<clang::VarDecl>(decl)->getCanonicalDecl(), expr_local_var_idx, false) &&
+ expr_local_var_idx != UINT32_MAX)
+ {
+ m_stream.PutHex8(DW_OP_APPLE_expr_local);
+ m_stream.PutULEB128(expr_local_var_idx);
+ }
+ else if (m_decl_map &&
+ m_decl_map->GetIndexForDecl(expr_local_var_idx, decl->getCanonicalDecl()))
+ {
+ m_stream.PutHex8(DW_OP_APPLE_extern);
+ m_stream.PutULEB128(expr_local_var_idx);
+ }
+ else
+ {
+ m_stream.PutHex8 (DW_OP_APPLE_error);
+ }
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitPredefinedExpr (clang::PredefinedExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitCharacterLiteral (clang::CharacterLiteral *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+ clang::QualType clang_type = Node->getType();
+ uint64_t clang_type_size = m_ast_context.getTypeSize (clang_type);
+ if (clang_type_size <= 64)
+ {
+ // Encode the integer into our DWARF expression
+ if (clang_type->isSignedIntegerType())
+ EncodeSInt64(Node->getValue(), clang_type_size);
+ else
+ EncodeUInt64(Node->getValue(), clang_type_size);
+ }
+ else
+ {
+ // TODO: eventually support integer math over 64 bits, probably using
+ // APInt as the class.
+ m_stream.PutHex8(DW_OP_APPLE_error);
+ }
+}
+
+bool
+lldb_private::ClangStmtVisitor::EncodeUInt64 (uint64_t uval, uint32_t bit_size)
+{
+ // If "bit_size" is zero, then encode "uval" in the most efficient way
+ if (bit_size <= 8 || (bit_size == 0 && uval <= UINT8_MAX))
+ {
+ m_stream.PutHex8 (DW_OP_const1u);
+ m_stream.PutHex8 (uval);
+ }
+ else if (bit_size <= 16 || (bit_size == 0 && uval <= UINT16_MAX))
+ {
+ m_stream.PutHex8 (DW_OP_const2u);
+ m_stream.PutHex16 (uval);
+ }
+ else if (bit_size <= 32 || (bit_size == 0 && uval <= UINT32_MAX))
+ {
+ m_stream.PutHex8 (DW_OP_const4u);
+ m_stream.PutHex32 (uval);
+ }
+ else if (bit_size <= 64 || (bit_size == 0))
+ {
+ m_stream.PutHex8 (DW_OP_const8u);
+ m_stream.PutHex64 (uval);
+ }
+ else
+ {
+ m_stream.PutHex8 (DW_OP_APPLE_error);
+ return false;
+ }
+ return true;
+}
+
+bool
+lldb_private::ClangStmtVisitor::EncodeSInt64 (int64_t sval, uint32_t bit_size)
+{
+ if (bit_size <= 8 || (bit_size == 0 && INT8_MIN <= sval && sval <= INT8_MAX))
+ {
+ m_stream.PutHex8 (DW_OP_const1s);
+ m_stream.PutHex8 (sval);
+ }
+ else if (bit_size <= 16 || (bit_size == 0 && INT16_MIN <= sval && sval <= INT16_MAX))
+ {
+ m_stream.PutHex8 (DW_OP_const2s);
+ m_stream.PutHex16 (sval);
+ }
+ else if (bit_size <= 32 || (bit_size == 0 && INT32_MIN <= sval && sval <= INT32_MAX))
+ {
+ m_stream.PutHex8 (DW_OP_const4s);
+ m_stream.PutHex32 (sval);
+ }
+ else if (bit_size <= 64 || (bit_size == 0))
+ {
+ m_stream.PutHex8 (DW_OP_const8s);
+ m_stream.PutHex64 (sval);
+ }
+ else
+ {
+ m_stream.PutHex8 (DW_OP_APPLE_error);
+ return false;
+ }
+ return true;
+}
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitIntegerLiteral (clang::IntegerLiteral *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+ const llvm::APInt &ap_int = Node->getValue();
+ if (ap_int.getBitWidth() <= 64)
+ {
+ clang::QualType clang_type = Node->getType();
+ uint64_t clang_type_size = m_ast_context.getTypeSize (clang_type);
+ // Encode the integer into our DWARF expression
+ if (clang_type->isSignedIntegerType())
+ EncodeSInt64(ap_int.getLimitedValue(), clang_type_size);
+ else
+ EncodeUInt64(ap_int.getLimitedValue(), clang_type_size);
+ }
+ else
+ {
+ // TODO: eventually support integer math over 64 bits, probably using
+ // APInt as the class.
+ m_stream.PutHex8(DW_OP_APPLE_error);
+ }
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitFloatingLiteral (clang::FloatingLiteral *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+ const llvm::APFloat &ap_float = Node->getValue();
+ // Put the length of the float in bytes into a single byte
+ llvm::APInt ap_int(ap_float.bitcastToAPInt());
+ const unsigned byte_size = ap_int.getBitWidth() / CHAR_BIT;
+ if (byte_size == sizeof(float))
+ {
+ if (sizeof(float) == 4)
+ {
+ m_stream.PutHex8(DW_OP_APPLE_constf);
+ m_stream.PutHex8 (byte_size);
+ m_stream.PutHex32 (ap_int.getLimitedValue());
+ return;
+ }
+ else if (sizeof(float) == 8)
+ {
+ m_stream.PutHex8(DW_OP_APPLE_constf);
+ m_stream.PutHex8 (byte_size);
+ m_stream.PutHex64 (ap_int.getLimitedValue());
+ return;
+ }
+ }
+ else if (byte_size == sizeof(double))
+ {
+ if (sizeof(double) == 4)
+ {
+ m_stream.PutHex8(DW_OP_APPLE_constf);
+ m_stream.PutHex8 (byte_size);
+ m_stream.PutHex32 (ap_int.getLimitedValue());
+ return;
+ }
+ else if (sizeof(double) == 8)
+ {
+ m_stream.PutHex8(DW_OP_APPLE_constf);
+ m_stream.PutHex8 (byte_size);
+ m_stream.PutHex64 (ap_int.getLimitedValue());
+ return;
+ }
+ }
+ else if (byte_size == sizeof(long double))
+ {
+ if (sizeof(long double) == 8)
+ {
+ m_stream.PutHex8(DW_OP_APPLE_constf);
+ m_stream.PutHex8 (byte_size);
+ m_stream.PutHex64 (ap_int.getLimitedValue());
+ return;
+ }
+ }
+ // TODO: eventually support float constants of all sizes using
+ // APFloat as the class.
+ m_stream.PutHex8(DW_OP_APPLE_error);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitStringLiteral (clang::StringLiteral *Str)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+
+ size_t byte_length = Str->getByteLength();
+ bool is_wide = Str->isWide();
+
+ size_t new_length = byte_length + (is_wide ? 1 : 2);
+
+ uint8_t null_terminated_string[new_length];
+
+ memcpy(&null_terminated_string[0], Str->getStrData(), byte_length);
+
+ if(is_wide)
+ {
+ null_terminated_string[byte_length] = '\0';
+ null_terminated_string[byte_length + 1] = '\0';
+ }
+ else
+ {
+ null_terminated_string[byte_length] = '\0';
+ }
+
+ Value *val = new Value(null_terminated_string, new_length);
+ val->SetContext(Value::eContextTypeOpaqueClangQualType, Str->getType().getAsOpaquePtr());
+
+ uint32_t val_idx = m_variable_list.AppendValue(val);
+
+ m_stream.PutHex8(DW_OP_APPLE_expr_local);
+ m_stream.PutULEB128(val_idx);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitUnaryOperator (clang::UnaryOperator *unary_op)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+
+ Visit(unary_op->getSubExpr());
+
+ switch (unary_op->getOpcode())
+ {
+ case clang::UnaryOperator::PostInc:
+ // Duplciate the top of stack value (which must be something that can
+ // be assignable/incremented) and push its current value
+ m_stream.PutHex8 (DW_OP_dup); // x, x
+ m_stream.PutHex8 (DW_OP_APPLE_value_of); // x, val(x)
+ m_stream.PutHex8 (DW_OP_swap); // val(x), x
+ m_stream.PutHex8 (DW_OP_dup); // val(x), x, x
+ m_stream.PutHex8 (DW_OP_lit1); // val(x), x, x, 1
+ m_stream.PutHex8 (DW_OP_plus); // val(x), x, val(x)+1
+ m_stream.PutHex8 (DW_OP_APPLE_assign); // val(x), x
+ m_stream.PutHex8 (DW_OP_drop); // val(x)
+ break;
+
+ case clang::UnaryOperator::PostDec:
+ // Duplciate the top of stack value (which must be something that can
+ // be assignable/incremented) and push its current value
+ m_stream.PutHex8 (DW_OP_dup); // x, x
+ m_stream.PutHex8 (DW_OP_APPLE_value_of); // x, val(x)
+ m_stream.PutHex8 (DW_OP_swap); // val(x), x
+ m_stream.PutHex8 (DW_OP_dup); // val(x), x, x
+ m_stream.PutHex8 (DW_OP_lit1); // val(x), x, x, 1
+ m_stream.PutHex8 (DW_OP_minus); // val(x), x, val(x)-1
+ m_stream.PutHex8 (DW_OP_APPLE_assign); // val(x), x
+ m_stream.PutHex8 (DW_OP_drop); // val(x)
+ break;
+
+ case clang::UnaryOperator::PreInc:
+ m_stream.PutHex8 (DW_OP_dup); // x, x
+ m_stream.PutHex8 (DW_OP_APPLE_value_of); // x, val(x)
+ m_stream.PutHex8 (DW_OP_lit1); // x, val(x), 1
+ m_stream.PutHex8 (DW_OP_plus); // x, val(x)+1
+ m_stream.PutHex8 (DW_OP_APPLE_assign); // x with new value
+ break;
+
+ case clang::UnaryOperator::PreDec:
+ m_stream.PutHex8 (DW_OP_dup); // x, x
+ m_stream.PutHex8 (DW_OP_APPLE_value_of); // x, val(x)
+ m_stream.PutHex8 (DW_OP_lit1); // x, val(x), 1
+ m_stream.PutHex8 (DW_OP_minus); // x, val(x)-1
+ m_stream.PutHex8 (DW_OP_APPLE_assign); // x with new value
+ break;
+
+ case clang::UnaryOperator::AddrOf:
+ m_stream.PutHex8 (DW_OP_APPLE_address_of);
+ break;
+
+ case clang::UnaryOperator::Deref:
+ m_stream.PutHex8 (DW_OP_APPLE_deref_type);
+ break;
+
+ case clang::UnaryOperator::Plus:
+ m_stream.PutHex8 (DW_OP_abs);
+ break;
+
+ case clang::UnaryOperator::Minus:
+ m_stream.PutHex8 (DW_OP_neg);
+ break;
+
+ case clang::UnaryOperator::Not:
+ m_stream.PutHex8 (DW_OP_not);
+ break;
+
+ case clang::UnaryOperator::LNot:
+ m_stream.PutHex8 (DW_OP_lit0);
+ m_stream.PutHex8 (DW_OP_eq);
+ break;
+
+ case clang::UnaryOperator::Real:
+ m_stream.PutHex8(DW_OP_APPLE_error);
+ break;
+
+ case clang::UnaryOperator::Imag:
+ m_stream.PutHex8(DW_OP_APPLE_error);
+ break;
+
+ case clang::UnaryOperator::Extension:
+ m_stream.PutHex8(DW_OP_APPLE_error);
+ break;
+
+ case clang::UnaryOperator::OffsetOf:
+ break;
+
+ default:
+ assert(!"Unknown unary operator!");
+ break;
+ }
+}
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitCastExpr (clang::CastExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+// CastExpr::CastKind cast_kind = Node->getCastKind();
+// switch (cast_kind)
+// {
+// case CastExpr::CK_Unknown:
+// case CastExpr::CK_BitCast: // Used for reinterpret_cast.
+// case CastExpr::CK_NoOp: // Used for const_cast.
+// case CastExpr::CK_BaseToDerived: // Base to derived class casts.
+// case CastExpr::CK_DerivedToBase: // Derived to base class casts.
+// case CastExpr::CK_Dynamic: // Dynamic cast.
+// case CastExpr::CK_ToUnion: // Cast to union (GCC extension).
+// case CastExpr::CK_ArrayToPointerDecay: // Array to pointer decay.
+// case CastExpr::CK_FunctionToPointerDecay: // Function to pointer decay.
+// case CastExpr::CK_NullToMemberPointer: // Null pointer to member pointer.
+// case CastExpr::CK_BaseToDerivedMemberPointer: // Member pointer in base class to member pointer in derived class.
+// case CastExpr::CK_DerivedToBaseMemberPointer: // Member pointer in derived class to member pointer in base class.
+// case CastExpr::CK_UserDefinedConversion: // Conversion using a user defined type conversion function.
+// case CastExpr::CK_ConstructorConversion: // Conversion by constructor
+// case CastExpr::CK_IntegralToPointer: // Integral to pointer
+// case CastExpr::CK_PointerToIntegral: // Pointer to integral
+// case CastExpr::CK_ToVoid: // Cast to void
+// case CastExpr::CK_VectorSplat: // Casting from an integer/floating type to an extended
+// // vector type with the same element type as the src type. Splats the
+// // src expression into the destination expression.
+// case CastExpr::CK_IntegralCast: // Casting between integral types of different size.
+// case CastExpr::CK_IntegralToFloating: // Integral to floating point.
+// case CastExpr::CK_FloatingToIntegral: // Floating point to integral.
+// case CastExpr::CK_FloatingCast: // Casting between floating types of different size.
+// m_stream.PutHex8(DW_OP_APPLE_error);
+// break;
+// }
+ uint32_t cast_type_count = 0;
+ lldb_private::Scalar::Type cast_type_encoding = GetScalarTypeForClangType (m_ast_context, Node->getType(), cast_type_count);
+
+
+ Visit (Node->getSubExpr());
+
+ // Simple scalar cast
+ if (cast_type_encoding != lldb_private::Scalar::e_void && cast_type_count == 1)
+ {
+ // Only cast if our scalar types mismatch
+ uint32_t castee_type_count = 0;
+ lldb_private::Scalar::Type castee_type_encoding = GetScalarTypeForClangType (m_ast_context, Node->getSubExpr()->getType(), castee_type_count);
+ if (cast_type_encoding != castee_type_encoding &&
+ castee_type_encoding != lldb_private::Scalar::e_void)
+ {
+ m_stream.PutHex8(DW_OP_APPLE_scalar_cast);
+ m_stream.PutHex8(cast_type_encoding);
+ }
+ }
+ else
+ {
+ // Handle more complex casts with clang types soon!
+ m_stream.PutHex8(DW_OP_APPLE_error);
+ }
+}
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitArraySubscriptExpr (clang::ArraySubscriptExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+ Visit (Node->getBase());
+ Visit (Node->getIdx());
+ m_stream.PutHex8(DW_OP_APPLE_array_ref);
+}
+
+//
+//CLANG_STMT_RESULT
+//lldb_private::ClangStmtVisitor::VisitImplicitCastExpr (clang::ImplicitCastExpr *Node)
+//{
+// DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+// m_stream.PutHex8(DW_OP_APPLE_scalar_cast);
+// Visit (Node->getSubExpr());
+//}
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitSizeOfAlignOfExpr (clang::SizeOfAlignOfExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitMemberExpr (clang::MemberExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+ clang::Expr *parent = Node->getBase();
+ Visit (parent);
+ clang::QualType parent_clang_type = parent->getType();
+ clang::NamedDecl *member_named_decl = cast<clang::NamedDecl>(Node->getMemberDecl()->getCanonicalDecl());
+
+// DeclarationName member_name = member->getDeclName();
+
+ clang::Type::TypeClass parent_type_class = parent_clang_type->getTypeClass();
+ if (parent_type_class == clang::Type::Pointer)
+ {
+ clang::PointerType *pointer_type = cast<clang::PointerType>(parent_clang_type.getTypePtr());
+ parent_clang_type = pointer_type->getPointeeType();
+ parent_type_class = parent_clang_type->getTypeClass();
+ }
+
+ switch (parent_type_class)
+ {
+ case clang::Type::Record:
+ {
+ const clang::RecordType *record_type = cast<clang::RecordType>(parent_clang_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ const clang::ASTRecordLayout &record_layout = m_ast_context.getASTRecordLayout(record_decl);
+ uint32_t field_idx = 0;
+ clang::RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx)
+ {
+ clang::NamedDecl *field_named_decl = cast<clang::NamedDecl>(field->getCanonicalDecl());
+ if (field_named_decl == member_named_decl)
+ {
+ std::pair<uint64_t, unsigned> field_type_info = m_ast_context.getTypeInfo(field->getType());
+ uint64_t field_bit_offset = record_layout.getFieldOffset (field_idx);
+ uint64_t field_byte_offset = field_bit_offset / 8;
+ uint32_t field_bitfield_bit_size = 0;
+ //uint32_t field_bitfield_bit_offset = field_bit_offset % 8;
+
+ if (field->isBitField())
+ {
+ clang::Expr* bit_width_expr = field->getBitWidth();
+ if (bit_width_expr)
+ {
+ llvm::APSInt bit_width_apsint;
+ if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, m_ast_context))
+ {
+ field_bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX);
+ }
+ }
+ }
+
+ if (Node->isArrow())
+ {
+ m_stream.PutHex8(DW_OP_deref);
+ }
+ else
+ {
+ m_stream.PutHex8(DW_OP_APPLE_address_of);
+ }
+
+ if (field_byte_offset)
+ {
+ if (EncodeUInt64(field_byte_offset, 0))
+ {
+ m_stream.PutHex8(DW_OP_plus);
+ }
+ }
+ m_stream.PutHex8(DW_OP_APPLE_clang_cast);
+ m_stream.PutPointer(field->getType().getAsOpaquePtr());
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ assert(!"Unhandled MemberExpr");
+ break;
+ }
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitExtVectorElementExpr (clang::ExtVectorElementExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitParenExpr(clang::ParenExpr *paren_expr)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+ Visit (paren_expr->getSubExpr());
+}
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitInitListExpr (clang::InitListExpr *init_list_expr)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitBinaryOperator (clang::BinaryOperator *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+
+ Visit(Node->getLHS());
+ Visit(Node->getRHS());
+
+ switch (Node->getOpcode())
+ {
+ default: assert(0 && "Unknown binary operator!");
+ case clang::BinaryOperator::PtrMemD: m_stream.PutHex8(DW_OP_APPLE_error); break;
+ case clang::BinaryOperator::PtrMemI: m_stream.PutHex8(DW_OP_APPLE_error); break;
+ case clang::BinaryOperator::Mul: m_stream.PutHex8(DW_OP_mul); break;
+ case clang::BinaryOperator::Div: m_stream.PutHex8(DW_OP_div); break;
+ case clang::BinaryOperator::Rem: m_stream.PutHex8(DW_OP_mod); break;
+ case clang::BinaryOperator::Add: m_stream.PutHex8(DW_OP_plus); break;
+ case clang::BinaryOperator::Sub: m_stream.PutHex8(DW_OP_minus); break;
+ case clang::BinaryOperator::Shl: m_stream.PutHex8(DW_OP_shl); break;
+ case clang::BinaryOperator::Shr: m_stream.PutHex8(DW_OP_shr); break;
+ case clang::BinaryOperator::LT: m_stream.PutHex8(DW_OP_lt); break;
+ case clang::BinaryOperator::GT: m_stream.PutHex8(DW_OP_gt); break;
+ case clang::BinaryOperator::LE: m_stream.PutHex8(DW_OP_le); break;
+ case clang::BinaryOperator::GE: m_stream.PutHex8(DW_OP_ge); break;
+ case clang::BinaryOperator::EQ: m_stream.PutHex8(DW_OP_eq); break;
+ case clang::BinaryOperator::NE: m_stream.PutHex8(DW_OP_ne); break;
+ case clang::BinaryOperator::And: m_stream.PutHex8(DW_OP_and); break;
+ case clang::BinaryOperator::Xor: m_stream.PutHex8(DW_OP_xor); break;
+ case clang::BinaryOperator::Or : m_stream.PutHex8(DW_OP_or); break;
+ case clang::BinaryOperator::LAnd:
+ // Do we need to call an operator here on objects? If so
+ // we will need a DW_OP_apple_logical_and
+ m_stream.PutHex8(DW_OP_lit0);
+ m_stream.PutHex8(DW_OP_ne);
+ m_stream.PutHex8(DW_OP_swap);
+ m_stream.PutHex8(DW_OP_lit0);
+ m_stream.PutHex8(DW_OP_ne);
+ m_stream.PutHex8(DW_OP_and);
+ break;
+
+ case clang::BinaryOperator::LOr :
+ // Do we need to call an operator here on objects? If so
+ // we will need a DW_OP_apple_logical_or
+ m_stream.PutHex8(DW_OP_lit0);
+ m_stream.PutHex8(DW_OP_ne);
+ m_stream.PutHex8(DW_OP_swap);
+ m_stream.PutHex8(DW_OP_lit0);
+ m_stream.PutHex8(DW_OP_ne);
+ m_stream.PutHex8(DW_OP_or);
+ break;
+
+ case clang::BinaryOperator::Assign:
+ m_stream.PutHex8(DW_OP_APPLE_assign);
+ break;
+
+ case clang::BinaryOperator::MulAssign:
+ m_stream.PutHex8(DW_OP_over);
+ m_stream.PutHex8(DW_OP_swap);
+ m_stream.PutHex8(DW_OP_mul);
+ m_stream.PutHex8(DW_OP_APPLE_assign);
+ break;
+
+ case clang::BinaryOperator::DivAssign:
+ m_stream.PutHex8(DW_OP_over);
+ m_stream.PutHex8(DW_OP_swap);
+ m_stream.PutHex8(DW_OP_div);
+ m_stream.PutHex8(DW_OP_APPLE_assign);
+ break;
+
+ case clang::BinaryOperator::RemAssign:
+ m_stream.PutHex8(DW_OP_over);
+ m_stream.PutHex8(DW_OP_swap);
+ m_stream.PutHex8(DW_OP_mod);
+ m_stream.PutHex8(DW_OP_APPLE_assign);
+ break;
+
+ case clang::BinaryOperator::AddAssign:
+ m_stream.PutHex8(DW_OP_over);
+ m_stream.PutHex8(DW_OP_swap);
+ m_stream.PutHex8(DW_OP_plus);
+ m_stream.PutHex8(DW_OP_APPLE_assign);
+ break;
+
+ case clang::BinaryOperator::SubAssign:
+ m_stream.PutHex8(DW_OP_over);
+ m_stream.PutHex8(DW_OP_swap);
+ m_stream.PutHex8(DW_OP_minus);
+ m_stream.PutHex8(DW_OP_APPLE_assign);
+ break;
+
+ case clang::BinaryOperator::ShlAssign:
+ m_stream.PutHex8(DW_OP_over);
+ m_stream.PutHex8(DW_OP_swap);
+ m_stream.PutHex8(DW_OP_shl);
+ m_stream.PutHex8(DW_OP_APPLE_assign);
+ break;
+
+ case clang::BinaryOperator::ShrAssign:
+ m_stream.PutHex8(DW_OP_over);
+ m_stream.PutHex8(DW_OP_swap);
+ m_stream.PutHex8(DW_OP_shr);
+ m_stream.PutHex8(DW_OP_APPLE_assign);
+ break;
+
+ case clang::BinaryOperator::AndAssign:
+ m_stream.PutHex8(DW_OP_over);
+ m_stream.PutHex8(DW_OP_swap);
+ m_stream.PutHex8(DW_OP_and);
+ m_stream.PutHex8(DW_OP_APPLE_assign);
+ break;
+
+ case clang::BinaryOperator::OrAssign:
+ m_stream.PutHex8(DW_OP_over);
+ m_stream.PutHex8(DW_OP_swap);
+ m_stream.PutHex8(DW_OP_or);
+ m_stream.PutHex8(DW_OP_APPLE_assign);
+ break;
+
+ case clang::BinaryOperator::XorAssign:
+ m_stream.PutHex8(DW_OP_over);
+ m_stream.PutHex8(DW_OP_swap);
+ m_stream.PutHex8(DW_OP_xor);
+ m_stream.PutHex8(DW_OP_APPLE_assign);
+ break;
+
+ case clang::BinaryOperator::Comma:
+ // Nothing needs to be done here right?
+ break;
+ }
+}
+
+
+//CLANG_STMT_RESULT
+//lldb_private::ClangStmtVisitor::VisitCompoundAssignOperator (CompoundAssignOperator *Node)
+//{
+// DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+//
+//}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitAddrLabelExpr (clang::AddrLabelExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitTypesCompatibleExpr (clang::TypesCompatibleExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+
+ // C++
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitCXXNamedCastExpr (clang::CXXNamedCastExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitCXXBoolLiteralExpr (clang::CXXBoolLiteralExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitCXXThisExpr (clang::CXXThisExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitCXXFunctionalCastExpr (clang::CXXFunctionalCastExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+
+ // ObjC
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitObjCEncodeExpr (clang::ObjCEncodeExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitObjCMessageExpr (clang::ObjCMessageExpr* Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitObjCSelectorExpr (clang::ObjCSelectorExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitObjCProtocolExpr (clang::ObjCProtocolExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitObjCPropertyRefExpr (clang::ObjCPropertyRefExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitObjCImplicitSetterGetterRefExpr (clang::ObjCImplicitSetterGetterRefExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitObjCIvarRefExpr (clang::ObjCIvarRefExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
+CLANG_STMT_RESULT
+lldb_private::ClangStmtVisitor::VisitObjCSuperExpr (clang::ObjCSuperExpr *Node)
+{
+ DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__);
+}
+
+
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
new file mode 100644
index 00000000000..d7afa36cea7
--- /dev/null
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -0,0 +1,2589 @@
+//===-- 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/dwarf.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Value.h"
+
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+
+#include "lldb/Host/Host.h"
+
+#include "lldb/lldb-private-log.h"
+
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Type.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.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_base_addr(),
+ m_expr_locals (NULL),
+ m_decl_map (NULL)
+{
+}
+
+DWARFExpression::DWARFExpression(const DWARFExpression& rhs) :
+ m_data(rhs.m_data),
+ m_reg_kind (rhs.m_reg_kind),
+ m_loclist_base_addr(rhs.m_loclist_base_addr),
+ m_expr_locals (rhs.m_expr_locals),
+ m_decl_map (rhs.m_decl_map)
+{
+}
+
+
+DWARFExpression::DWARFExpression(const DataExtractor& data, uint32_t data_offset, uint32_t data_length, const Address* loclist_base_addr_ptr) :
+ m_data(data, data_offset, data_length),
+ m_reg_kind (eRegisterKindDWARF),
+ m_loclist_base_addr(),
+ m_expr_locals (NULL),
+ m_decl_map (NULL)
+{
+ if (loclist_base_addr_ptr)
+ m_loclist_base_addr = *loclist_base_addr_ptr;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DWARFExpression::~DWARFExpression()
+{
+}
+
+
+bool
+DWARFExpression::IsValid() const
+{
+ return m_data.GetByteSize() > 0;
+}
+
+
+void
+DWARFExpression::SetExpressionLocalVariableList (ClangExpressionVariableList *locals)
+{
+ m_expr_locals = locals;
+}
+
+void
+DWARFExpression::SetExpressionDeclMap (ClangExpressionDeclMap *decl_map)
+{
+ m_decl_map = decl_map;
+}
+
+void
+DWARFExpression::SetOpcodeData (const DataExtractor& data, const Address* loclist_base_addr_ptr)
+{
+ m_data = data;
+ if (loclist_base_addr_ptr != NULL)
+ m_loclist_base_addr = *loclist_base_addr_ptr;
+ else
+ m_loclist_base_addr.Clear();
+}
+
+void
+DWARFExpression::SetOpcodeData (const DataExtractor& data, uint32_t data_offset, uint32_t data_length, const Address* loclist_base_addr_ptr)
+{
+ m_data.SetData(data, data_offset, data_length);
+ if (loclist_base_addr_ptr != NULL)
+ m_loclist_base_addr = *loclist_base_addr_ptr;
+ else
+ m_loclist_base_addr.Clear();
+}
+
+void
+DWARFExpression::DumpLocation (Stream *s, uint32_t offset, uint32_t length, lldb::DescriptionLevel level) const
+{
+ if (!m_data.ValidOffsetForDataOfSize(offset, length))
+ return;
+ const uint32_t start_offset = offset;
+ const uint32_t end_offset = offset + length;
+ while (m_data.ValidOffset(offset) && offset < end_offset)
+ {
+ const uint32_t op_offset = offset;
+ const uint8_t op = m_data.GetU8(&offset);
+
+ switch (level)
+ {
+ 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.8x: %s", op_offset, op >= DW_OP_APPLE_uninit ? "DW_OP_APPLE_" : "DW_OP_");
+ break;
+ }
+
+ switch (op)
+ {
+ case DW_OP_addr: *s << "addr(" << m_data.GetAddress(&offset) << ") "; break; // 0x03 1 address
+ case DW_OP_deref: *s << "deref"; break; // 0x06
+ case DW_OP_const1u: s->Printf("const1u(0x%2.2x) ", m_data.GetU8(&offset)); break; // 0x08 1 1-byte constant
+ case DW_OP_const1s: s->Printf("const1s(0x%2.2x) ", m_data.GetU8(&offset)); break; // 0x09 1 1-byte constant
+ case DW_OP_const2u: s->Printf("const2u(0x%4.4x) ", m_data.GetU16(&offset)); break; // 0x0a 1 2-byte constant
+ case DW_OP_const2s: s->Printf("const2s(0x%4.4x) ", m_data.GetU16(&offset)); break; // 0x0b 1 2-byte constant
+ case DW_OP_const4u: s->Printf("const4u(0x%8.8x) ", m_data.GetU32(&offset)); break; // 0x0c 1 4-byte constant
+ case DW_OP_const4s: s->Printf("const4s(0x%8.8x) ", m_data.GetU32(&offset)); break; // 0x0d 1 4-byte constant
+ case DW_OP_const8u: s->Printf("const8u(0x%16.16llx) ", m_data.GetU64(&offset)); break; // 0x0e 1 8-byte constant
+ case DW_OP_const8s: s->Printf("const8s(0x%16.16llx) ", m_data.GetU64(&offset)); break; // 0x0f 1 8-byte constant
+ case DW_OP_constu: s->Printf("constu(0x%x) ", m_data.GetULEB128(&offset)); break; // 0x10 1 ULEB128 constant
+ case DW_OP_consts: s->Printf("consts(0x%x) ", m_data.GetSLEB128(&offset)); break; // 0x11 1 SLEB128 constant
+ case DW_OP_dup: s->PutCString("dup"); break; // 0x12
+ case DW_OP_drop: s->PutCString("drop"); break; // 0x13
+ case DW_OP_over: s->PutCString("over"); break; // 0x14
+ case DW_OP_pick: s->Printf("pick(0x%2.2x) ", m_data.GetU8(&offset)); break; // 0x15 1 1-byte stack index
+ case DW_OP_swap: s->PutCString("swap"); break; // 0x16
+ case DW_OP_rot: s->PutCString("rot"); break; // 0x17
+ case DW_OP_xderef: s->PutCString("xderef"); break; // 0x18
+ case DW_OP_abs: s->PutCString("abs"); break; // 0x19
+ case DW_OP_and: s->PutCString("and"); break; // 0x1a
+ case DW_OP_div: s->PutCString("div"); break; // 0x1b
+ case DW_OP_minus: s->PutCString("minus"); break; // 0x1c
+ case DW_OP_mod: s->PutCString("mod"); break; // 0x1d
+ case DW_OP_mul: s->PutCString("mul"); break; // 0x1e
+ case DW_OP_neg: s->PutCString("neg"); break; // 0x1f
+ case DW_OP_not: s->PutCString("not"); break; // 0x20
+ case DW_OP_or: s->PutCString("or"); break; // 0x21
+ case DW_OP_plus: s->PutCString("plus"); break; // 0x22
+ case DW_OP_plus_uconst: // 0x23 1 ULEB128 addend
+ s->Printf("plus_uconst(0x%x) ", m_data.GetULEB128(&offset));
+ break;
+
+ case DW_OP_shl: s->PutCString("shl"); break; // 0x24
+ case DW_OP_shr: s->PutCString("shr"); break; // 0x25
+ case DW_OP_shra: s->PutCString("shra"); break; // 0x26
+ case DW_OP_xor: s->PutCString("xor"); break; // 0x27
+ case DW_OP_skip: s->Printf("skip(0x%4.4x)", m_data.GetU16(&offset)); break; // 0x2f 1 signed 2-byte constant
+ case DW_OP_bra: s->Printf("bra(0x%4.4x)", m_data.GetU16(&offset)); break; // 0x28 1 signed 2-byte constant
+ case DW_OP_eq: s->PutCString("eq"); break; // 0x29
+ case DW_OP_ge: s->PutCString("ge"); break; // 0x2a
+ case DW_OP_gt: s->PutCString("gt"); break; // 0x2b
+ case DW_OP_le: s->PutCString("le"); break; // 0x2c
+ case DW_OP_lt: s->PutCString("lt"); break; // 0x2d
+ case DW_OP_ne: s->PutCString("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("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: s->Printf("reg%i", op - DW_OP_reg0); break; // 0x6f
+
+ 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: s->Printf("breg%i(0x%x)", op - DW_OP_breg0, m_data.GetULEB128(&offset)); break;
+
+ case DW_OP_regx: // 0x90 1 ULEB128 register
+ s->Printf("regx(0x%x)", m_data.GetULEB128(&offset));
+ break;
+ case DW_OP_fbreg: // 0x91 1 SLEB128 offset
+ s->Printf("fbreg(0x%x)",m_data.GetSLEB128(&offset));
+ break;
+ case DW_OP_bregx: // 0x92 2 ULEB128 register followed by SLEB128 offset
+ s->Printf("bregx(0x%x, 0x%x)", m_data.GetULEB128(&offset), m_data.GetSLEB128(&offset));
+ break;
+ case DW_OP_piece: // 0x93 1 ULEB128 size of piece addressed
+ s->Printf("piece(0x%x)", m_data.GetULEB128(&offset));
+ break;
+ case DW_OP_deref_size: // 0x94 1 1-byte size of data retrieved
+ s->Printf("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("xderef_size(0x%2.2x)", m_data.GetU8(&offset));
+ break;
+ case DW_OP_nop: s->PutCString("nop"); break; // 0x96
+ case DW_OP_push_object_address: s->PutCString("push_object_address"); break; // 0x97 DWARF3
+ case DW_OP_call2: // 0x98 DWARF3 1 2-byte offset of DIE
+ s->Printf("call2(0x%4.4x)", m_data.GetU16(&offset));
+ break;
+ case DW_OP_call4: // 0x99 DWARF3 1 4-byte offset of DIE
+ s->Printf("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("call_ref(0x%8.8llx)", 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("bit_piece(0x%x, 0x%x)", m_data.GetULEB128(&offset), m_data.GetULEB128(&offset));
+// break;
+// case DW_OP_lo_user: s->PutCString("lo_user"); break; // 0xe0
+// case DW_OP_hi_user: s->PutCString("hi_user"); break; // 0xff
+ case DW_OP_APPLE_extern:
+ s->Printf("extern(%u)", m_data.GetULEB128(&offset));
+ break;
+ case DW_OP_APPLE_array_ref:
+ s->PutCString("array_ref");
+ break;
+ case DW_OP_APPLE_uninit:
+ s->PutCString("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("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("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("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("deref_type");
+ break;
+ case DW_OP_APPLE_expr_local: // 0xF5 - ULEB128 expression local index
+ s->Printf("expr_local(%u)", 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("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("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("clang_cast(%p)", clang_type);
+ }
+ break;
+ case DW_OP_APPLE_clear:
+ s->PutCString("clear");
+ break;
+ case DW_OP_APPLE_error: // 0xFF - Stops expression evaluation and returns an error (no args)
+ s->PutCString("error");
+ break;
+ }
+ }
+}
+
+void
+DWARFExpression::SetLocationListBaseAddress(Address& base_addr)
+{
+ m_loclist_base_addr = base_addr;
+}
+
+int
+DWARFExpression::GetRegisterKind ()
+{
+ return m_reg_kind;
+}
+
+void
+DWARFExpression::SetRegisterKind (int reg_kind)
+{
+ m_reg_kind = reg_kind;
+}
+
+bool
+DWARFExpression::IsLocationList() const
+{
+ return m_loclist_base_addr.IsSectionOffset();
+}
+
+void
+DWARFExpression::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ if (IsLocationList())
+ {
+ // We have a location list
+ uint32_t offset = 0;
+ uint32_t count = 0;
+ Address base_addr(m_loclist_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(", ");
+ AddressRange addr_range(base_addr, end_addr_offset - begin_addr_offset);
+ addr_range.GetBaseAddress().SetOffset(base_addr.GetOffset() + begin_addr_offset);
+ addr_range.Dump (s, NULL, Address::DumpStyleFileAddress);
+ s->PutChar('{');
+ uint32_t location_length = m_data.GetU16(&offset);
+ DumpLocation (s, offset, location_length, level);
+ 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 == 0xFFFFFFFFull ||
+ m_data.GetAddressByteSize() == 8 && begin_addr_offset == 0xFFFFFFFFFFFFFFFFull)
+ {
+ // 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);
+ }
+}
+
+static bool
+ReadRegisterValueAsScalar
+(
+ ExecutionContext *exe_ctx,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ Error *error_ptr,
+ Value &value
+)
+{
+ if (exe_ctx && exe_ctx->frame)
+ {
+ RegisterContext *reg_context = exe_ctx->frame->GetRegisterContext();
+
+ if (reg_context == NULL)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("No register context in frame.\n");
+ }
+ else
+ {
+ uint32_t native_reg = reg_context->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
+ {
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeDCRegisterInfo, const_cast<RegisterInfo *>(reg_context->GetRegisterInfoAtIndex(native_reg)));
+
+ if (reg_context->ReadRegisterValue (native_reg, value.GetScalar()))
+ return true;
+
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Failed to read register %u.\n", native_reg);
+ }
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Invalid frame in execution context.\n");
+ }
+ return false;
+}
+
+bool
+DWARFExpression::LocationListContainsLoadAddress (Process* process, const Address &addr) const
+{
+ if (IsLocationList())
+ {
+ uint32_t offset = 0;
+ const addr_t load_addr = addr.GetLoadAddress(process);
+
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ addr_t loc_list_base_addr = m_loclist_base_addr.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;
+}
+bool
+DWARFExpression::Evaluate
+(
+ ExecutionContextScope *exe_scope,
+ clang::ASTContext *ast_context,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr
+) const
+{
+ ExecutionContext exe_ctx (exe_scope);
+ return Evaluate(&exe_ctx, ast_context, initial_value_ptr, result, error_ptr);
+}
+
+bool
+DWARFExpression::Evaluate
+(
+ ExecutionContext *exe_ctx,
+ clang::ASTContext *ast_context,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr
+) const
+{
+ if (IsLocationList())
+ {
+ uint32_t offset = 0;
+ addr_t pc = exe_ctx->frame->GetPC().GetLoadAddress(exe_ctx->process);
+
+ if (pc == LLDB_INVALID_ADDRESS)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid PC in frame.");
+ return false;
+ }
+
+ addr_t loc_list_base_addr = m_loclist_base_addr.GetLoadAddress(exe_ctx->process);
+
+ if (loc_list_base_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Out of scope.");
+ 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;
+
+ uint16_t length = m_data.GetU16(&offset);
+
+ if (length > 0 && lo_pc <= pc && pc < hi_pc)
+ {
+ return DWARFExpression::Evaluate (exe_ctx, ast_context, m_data, m_expr_locals, m_decl_map, offset, length, m_reg_kind, initial_value_ptr, result, error_ptr);
+ }
+ offset += length;
+ }
+ }
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Out of scope.\n", pc);
+ return false;
+ }
+
+ // Not a location list, just a single expression.
+ return DWARFExpression::Evaluate (exe_ctx, ast_context, m_data, m_expr_locals, m_decl_map, 0, m_data.GetByteSize(), m_reg_kind, initial_value_ptr, result, error_ptr);
+}
+
+
+
+bool
+DWARFExpression::Evaluate
+(
+ ExecutionContext *exe_ctx,
+ clang::ASTContext *ast_context,
+ const DataExtractor& opcodes,
+ ClangExpressionVariableList *expr_locals,
+ ClangExpressionDeclMap *decl_map,
+ const uint32_t opcodes_offset,
+ const uint32_t opcodes_length,
+ const uint32_t reg_kind,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr
+)
+{
+ std::vector<Value> stack;
+
+ if (initial_value_ptr)
+ stack.push_back(*initial_value_ptr);
+
+ uint32_t offset = opcodes_offset;
+ const uint32_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 uint32_t op_offset = offset;
+ const uint8_t op = opcodes.GetU8(&offset);
+
+ if (log)
+ {
+ log->Printf("\n");
+ size_t count = stack.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ StreamString new_value;
+ new_value.Printf("[%zu]", i);
+ stack[i].Dump(&new_value);
+ log->Printf("%s", new_value.GetData());
+ }
+ log->Printf("0x%8.8x: %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(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 (exe_ctx->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 = exe_ctx->process->GetAddressByteSize();
+ Error error;
+ if (exe_ctx->process->ReadMemory(pointer_addr, &addr_bytes, addr_size, error) == addr_size)
+ {
+ DataExtractor addr_data(addr_bytes, sizeof(addr_bytes), exe_ctx->process->GetByteOrder(), addr_size);
+ uint32_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%llx 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:
+ if (error_ptr)
+ error_ptr->SetErrorString("Unimplemented opcode: DW_OP_deref_size.");
+ return false;
+
+ //----------------------------------------------------------------------
+ // 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(( uint8_t)opcodes.GetU8(&offset)); break;
+ case DW_OP_const1s : stack.push_back(( int8_t)opcodes.GetU8(&offset)); break;
+ case DW_OP_const2u : stack.push_back((uint16_t)opcodes.GetU16(&offset)); break;
+ case DW_OP_const2s : stack.push_back(( int16_t)opcodes.GetU16(&offset)); break;
+ case DW_OP_const4u : stack.push_back((uint32_t)opcodes.GetU32(&offset)); break;
+ case DW_OP_const4s : stack.push_back(( int32_t)opcodes.GetU32(&offset)); break;
+ case DW_OP_const8u : stack.push_back((uint64_t)opcodes.GetU64(&offset)); break;
+ case DW_OP_const8s : stack.push_back(( int64_t)opcodes.GetU64(&offset)); break;
+ case DW_OP_constu : stack.push_back(opcodes.GetULEB128(&offset)); break;
+ case DW_OP_consts : stack.push_back(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, ast_context).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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) & tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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, ast_context).IsZero())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Divide by zero.");
+ return false;
+ }
+ else
+ {
+ stack.pop_back();
+ stack.back() = stack.back().ResolveValue(exe_ctx, ast_context) / tmp.ResolveValue(exe_ctx, ast_context);
+ if (!stack.back().ResolveValue(exe_ctx, ast_context).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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) - tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) % tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) * tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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, ast_context).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, ast_context).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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) | tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) + tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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
+ {
+ uint32_t uconst_value = opcodes.GetULEB128(&offset);
+ // Implicit conversion from a UINT to a Scalar...
+ stack.back().ResolveValue(exe_ctx, ast_context) += uconst_value;
+ if (!stack.back().ResolveValue(exe_ctx, ast_context).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, ast_context) <<= tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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, ast_context).ShiftRightLogical(tmp.ResolveValue(exe_ctx, ast_context)) == 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, ast_context) >>= tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) ^ tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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);
+ uint32_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, ast_context) != zero)
+ {
+ uint32_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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) == tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) >= tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) > tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) <= tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) < tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) != tmp.ResolveValue(exe_ctx, ast_context);
+ }
+ 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(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 (exe_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 (exe_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 (exe_ctx, reg_kind, reg_num, error_ptr, tmp))
+ {
+ int64_t breg_offset = opcodes.GetSLEB128(&offset);
+ tmp.ResolveValue(exe_ctx, ast_context) += (uint64_t)breg_offset;
+ 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 (exe_ctx, reg_kind, reg_num, error_ptr, tmp))
+ {
+ int64_t breg_offset = opcodes.GetSLEB128(&offset);
+ tmp.ResolveValue(exe_ctx, ast_context) += (uint64_t)breg_offset;
+ stack.push_back(tmp);
+ stack.back().SetValueType (Value::eValueTypeLoadAddress);
+ }
+ else
+ return false;
+ }
+ break;
+
+ case DW_OP_fbreg:
+ if (exe_ctx && exe_ctx->frame)
+ {
+ Scalar value;
+ if (exe_ctx->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;
+ }
+ 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_call_ref
+ // OPERANDS:
+ // uint32_t absolute DIE offset for 32-bit DWARF or a uint64_t
+ // absolute DIE offset for 64 bit DWARF.
+ // DESCRIPTION: Performs a subroutine call during evaluation of a DWARF
+ // expression. Takes a single operand. In the 32-bit DWARF format, the
+ // operand is a 4-byte unsigned value; in the 64-bit DWARF format, it
+ // is an 8-byte unsigned value. The operand is used as the offset of a
+ // debugging information entry in a .debug_info section which may be
+ // contained in a shared object for executable other than that
+ // containing the operator. For references from one shared object or
+ // executable to another, the relocation must be performed by the
+ // consumer.
+ //
+ // Operand interpretation of DW_OP_call_ref is exactly like that for
+ // DW_FORM_ref_addr.
+ //
+ // 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_call_ref:
+ if (error_ptr)
+ error_ptr->SetErrorString ("Unimplemented opcode DW_OP_call_ref.");
+ return false;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_APPLE_array_ref
+ // OPERANDS: none
+ // DESCRIPTION: Pops a value off the stack and uses it as the array
+ // index. Pops a second value off the stack and uses it as the array
+ // itself. Pushes a value onto the stack representing the element of
+ // the array specified by the index.
+ //----------------------------------------------------------------------
+ case DW_OP_APPLE_array_ref:
+ {
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_APPLE_array_ref.");
+ return false;
+ }
+
+ Value index_val = stack.back();
+ stack.pop_back();
+ Value array_val = stack.back();
+ stack.pop_back();
+
+ Scalar &index_scalar = index_val.ResolveValue(exe_ctx, ast_context);
+ int64_t index = index_scalar.SLongLong(LONG_LONG_MAX);
+
+ if (index == LONG_LONG_MAX)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid array index.");
+ return false;
+ }
+
+ if (array_val.GetContextType() != Value::eContextTypeOpaqueClangQualType)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Arrays without Clang types are unhandled at this time.");
+ return false;
+ }
+
+ if (array_val.GetValueType() != Value::eValueTypeLoadAddress &&
+ array_val.GetValueType() != Value::eValueTypeHostAddress)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Array must be stored in memory.");
+ return false;
+ }
+
+ void *array_type = array_val.GetOpaqueClangQualType();
+
+ void *member_type;
+ uint64_t size = 0;
+
+ if ((!ClangASTContext::IsPointerType(array_type, &member_type)) &&
+ (!ClangASTContext::IsArrayType(array_type, &member_type, &size)))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Array reference from something that is neither a pointer nor an array.");
+ return false;
+ }
+
+ if (size && (index >= size || index < 0))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Out of bounds array access. %lld is not in [0, %llu]", index, size);
+ return false;
+ }
+
+ uint64_t member_bit_size = ClangASTContext::GetTypeBitSize(ast_context, member_type);
+ uint64_t member_bit_align = ClangASTContext::GetTypeBitAlign(ast_context, member_type);
+ uint64_t member_bit_incr = ((member_bit_size + member_bit_align - 1) / member_bit_align) * member_bit_align;
+ if (member_bit_incr % 8)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Array increment is not byte aligned", index, size);
+ return false;
+ }
+ int64_t member_offset = (int64_t)(member_bit_incr / 8) * index;
+
+ Value member;
+
+ member.SetContext(Value::eContextTypeOpaqueClangQualType, member_type);
+ member.SetValueType(array_val.GetValueType());
+
+ addr_t array_base = (addr_t)array_val.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ addr_t member_loc = array_base + member_offset;
+ member.GetScalar() = (uint64_t)member_loc;
+
+ stack.push_back(member);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_APPLE_uninit
+ // OPERANDS: none
+ // DESCRIPTION: Lets us know that the value is currently not initialized
+ //----------------------------------------------------------------------
+ case DW_OP_APPLE_uninit:
+ //return eResultTypeErrorUninitialized;
+ break; // Ignore this as we have seen cases where this value is incorrectly added
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_APPLE_assign
+ // OPERANDS: none
+ // DESCRIPTION: Pops a value off of the stack and assigns it to the next
+ // item on the stack which must be something assignable (inferior
+ // Variable, inferior Type with address, inferior register, or
+ // expression local variable.
+ //----------------------------------------------------------------------
+ case DW_OP_APPLE_assign:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_APPLE_assign.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ Value::ContextType context_type = stack.back().GetContextType();
+ StreamString new_value(Stream::eBinary, 4, eByteOrderHost);
+ switch (context_type)
+ {
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ void *clang_type = stack.back().GetOpaqueClangQualType();
+
+ if (ClangASTContext::IsAggregateType (clang_type))
+ {
+ Value::ValueType source_value_type = tmp.GetValueType();
+ Value::ValueType target_value_type = stack.back().GetValueType();
+
+ addr_t source_addr = (addr_t)tmp.GetScalar().ULongLong();
+ addr_t target_addr = (addr_t)stack.back().GetScalar().ULongLong();
+
+ size_t byte_size = (ClangASTContext::GetTypeBitSize(ast_context, clang_type) + 7) / 8;
+
+ switch (source_value_type)
+ {
+ case Value::eValueTypeLoadAddress:
+ switch (target_value_type)
+ {
+ case Value::eValueTypeLoadAddress:
+ {
+ DataBufferHeap data;
+ data.SetByteSize(byte_size);
+
+ Error error;
+ if (exe_ctx->process->ReadMemory (source_addr, data.GetBytes(), byte_size, error) != byte_size)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Couldn't read a composite type from the target: %s", error.AsCString());
+ return false;
+ }
+
+ if (exe_ctx->process->WriteMemory (target_addr, data.GetBytes(), byte_size, error) != byte_size)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Couldn't write a composite type to the target: %s", error.AsCString());
+ return false;
+ }
+ }
+ break;
+ case Value::eValueTypeHostAddress:
+ if (exe_ctx->process->GetByteOrder() != Host::GetByteOrder())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Copy of composite types between incompatible byte orders is unimplemented");
+ return false;
+ }
+ else
+ {
+ Error error;
+ if (exe_ctx->process->ReadMemory (source_addr, (uint8_t*)target_addr, byte_size, error) != byte_size)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Couldn't read a composite type from the target: %s", error.AsCString());
+ return false;
+ }
+ }
+ break;
+ default:
+ return false;
+ }
+ break;
+ case Value::eValueTypeHostAddress:
+ switch (target_value_type)
+ {
+ case Value::eValueTypeLoadAddress:
+ if (exe_ctx->process->GetByteOrder() != Host::GetByteOrder())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Copy of composite types between incompatible byte orders is unimplemented");
+ return false;
+ }
+ else
+ {
+ Error error;
+ if (exe_ctx->process->WriteMemory (target_addr, (uint8_t*)source_addr, byte_size, error) != byte_size)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Couldn't write a composite type to the target: %s", error.AsCString());
+ return false;
+ }
+ }
+ case Value::eValueTypeHostAddress:
+ memcpy ((uint8_t*)target_addr, (uint8_t*)source_addr, byte_size);
+ break;
+ default:
+ return false;
+ }
+ }
+ }
+ else
+ {
+ if (!Type::SetValueFromScalar(ast_context,
+ clang_type,
+ tmp.ResolveValue(exe_ctx, ast_context),
+ new_value))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Couldn't extract a value from an integral type.\n");
+ return false;
+ }
+
+ Value::ValueType value_type = stack.back().GetValueType();
+
+ switch (value_type)
+ {
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeHostAddress:
+ {
+ lldb::AddressType address_type = (value_type == Value::eValueTypeLoadAddress ? eAddressTypeLoad : eAddressTypeHost);
+ lldb::addr_t addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ if (!Type::WriteToMemory (exe_ctx,
+ ast_context,
+ clang_type,
+ addr,
+ address_type,
+ new_value))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Failed to write value to memory at 0x%llx.\n", addr);
+ return false;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ if (error_ptr)
+ error_ptr->SetErrorString ("Assign failed.");
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_APPLE_address_of
+ // OPERANDS: none
+ // DESCRIPTION: Pops a value off of the stack and pushed its address.
+ // The top item on the stack must be a variable, or already be a memory
+ // location.
+ //----------------------------------------------------------------------
+ case DW_OP_APPLE_address_of:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_APPLE_address_of.");
+ return false;
+ }
+ else
+ {
+ Value::ValueType value_type = stack.back().GetValueType();
+ switch (value_type)
+ {
+ default:
+ case Value::eValueTypeScalar: // raw scalar value
+ if (error_ptr)
+ error_ptr->SetErrorString("Top stack item isn't a memory based object.");
+ return false;
+
+ case Value::eValueTypeLoadAddress: // load address value
+ case Value::eValueTypeFileAddress: // file address value
+ case Value::eValueTypeHostAddress: // host address value (for memory in the process that is using liblldb)
+ // Taking the address of an object reduces it to the address
+ // of the value and removes any extra context it had.
+ //stack.back().SetValueType(Value::eValueTypeScalar);
+ stack.back().ClearContext();
+ break;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_APPLE_value_of
+ // OPERANDS: none
+ // DESCRIPTION: Pops a value off of the stack and pushed its value.
+ // The top item on the stack must be a variable, expression variable.
+ //----------------------------------------------------------------------
+ case DW_OP_APPLE_value_of:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 items for DW_OP_APPLE_value_of.");
+ return false;
+ }
+ else if (!stack.back().ValueOf(exe_ctx, ast_context))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("Top stack item isn't a valid candidate for DW_OP_APPLE_value_of.");
+ return false;
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_APPLE_deref_type
+ // OPERANDS: none
+ // DESCRIPTION: gets the value pointed to by the top stack item
+ //----------------------------------------------------------------------
+ case DW_OP_APPLE_deref_type:
+ {
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 items for DW_OP_APPLE_deref_type.");
+ return false;
+ }
+
+ tmp = stack.back();
+ stack.pop_back();
+
+ if (tmp.GetContextType() != Value::eContextTypeOpaqueClangQualType)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Item at top of expression stack must have a Clang type");
+ return false;
+ }
+
+ void *ptr_type = tmp.GetOpaqueClangQualType();
+ void *target_type;
+
+ if (!ClangASTContext::IsPointerType(ptr_type, &target_type))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Dereferencing a non-pointer type");
+ return false;
+ }
+
+ // TODO do we want all pointers to be dereferenced as load addresses?
+ Value::ValueType value_type = tmp.GetValueType();
+
+ tmp.ResolveValue(exe_ctx, ast_context);
+
+ tmp.SetValueType(value_type);
+ tmp.SetContext(Value::eContextTypeOpaqueClangQualType, target_type);
+
+ stack.push_back(tmp);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_APPLE_expr_local
+ // OPERANDS: ULEB128
+ // DESCRIPTION: pushes the expression local variable index onto the
+ // stack and set the appropriate context so we know the stack item is
+ // an expression local variable index.
+ //----------------------------------------------------------------------
+ case DW_OP_APPLE_expr_local:
+ {
+ uint32_t idx = opcodes.GetULEB128(&offset);
+ if (expr_locals == NULL)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("DW_OP_APPLE_expr_local(%u) opcode encountered with no local variable list.\n", idx);
+ return false;
+ }
+ Value *expr_local_variable = expr_locals->GetVariableAtIndex(idx);
+ if (expr_local_variable == NULL)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("DW_OP_APPLE_expr_local(%u) with invalid index %u.\n", idx, idx);
+ return false;
+ }
+ Value *proxy = expr_local_variable->CreateProxy();
+ stack.push_back(*proxy);
+ delete proxy;
+ //stack.back().SetContext (Value::eContextTypeOpaqueClangQualType, expr_local_variable->GetOpaqueClangQualType());
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_APPLE_extern
+ // OPERANDS: ULEB128
+ // DESCRIPTION: pushes a proxy for the extern object index onto the
+ // stack.
+ //----------------------------------------------------------------------
+ case DW_OP_APPLE_extern:
+ {
+ uint32_t idx = opcodes.GetULEB128(&offset);
+ if (!decl_map)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("DW_OP_APPLE_extern(%u) opcode encountered with no decl map.\n", idx);
+ return false;
+ }
+ Value *extern_var = decl_map->GetValueForIndex(idx);
+ if (!extern_var)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("DW_OP_APPLE_extern(%u) with invalid index %u.\n", idx, idx);
+ return false;
+ }
+ Value *proxy = extern_var->CreateProxy();
+ stack.push_back(*proxy);
+ delete proxy;
+ }
+ break;
+
+ case DW_OP_APPLE_scalar_cast:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_APPLE_scalar_cast.");
+ return false;
+ }
+ else
+ {
+ // Simple scalar cast
+ if (!stack.back().ResolveValue(exe_ctx, ast_context).Cast((Scalar::Type)opcodes.GetU8(&offset)))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Cast failed.");
+ return false;
+ }
+ }
+ break;
+
+
+ case DW_OP_APPLE_clang_cast:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_APPLE_clang_cast.");
+ return false;
+ }
+ else
+ {
+ void *clang_type = (void *)opcodes.GetMaxU64(&offset, sizeof(void*));
+ stack.back().SetContext (Value::eContextTypeOpaqueClangQualType, clang_type);
+ }
+ break;
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_APPLE_constf
+ // OPERANDS: 1 byte float length, followed by that many bytes containing
+ // the constant float data.
+ // DESCRIPTION: Push a float value onto the expression stack.
+ //----------------------------------------------------------------------
+ case DW_OP_APPLE_constf: // 0xF6 - 1 byte float size, followed by constant float data
+ {
+ uint8_t float_length = opcodes.GetU8(&offset);
+ if (sizeof(float) == float_length)
+ tmp.ResolveValue(exe_ctx, ast_context) = opcodes.GetFloat (&offset);
+ else if (sizeof(double) == float_length)
+ tmp.ResolveValue(exe_ctx, ast_context) = opcodes.GetDouble (&offset);
+ else if (sizeof(long double) == float_length)
+ tmp.ResolveValue(exe_ctx, ast_context) = opcodes.GetLongDouble (&offset);
+ else
+ {
+ StreamString new_value;
+ opcodes.Dump(&new_value, offset, eFormatBytes, 1, float_length, UINT32_MAX, DW_INVALID_ADDRESS, 0, 0);
+
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("DW_OP_APPLE_constf(<%u> %s) unsupported float size.\n", float_length, new_value.GetData());
+ return false;
+ }
+ tmp.SetValueType(Value::eValueTypeScalar);
+ tmp.ClearContext();
+ stack.push_back(tmp);
+ }
+ break;
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_APPLE_clear
+ // OPERANDS: none
+ // DESCRIPTION: Clears the expression stack.
+ //----------------------------------------------------------------------
+ case DW_OP_APPLE_clear:
+ stack.clear();
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_APPLE_error
+ // OPERANDS: none
+ // DESCRIPTION: Pops a value off of the stack and pushed its value.
+ // The top item on the stack must be a variable, expression variable.
+ //----------------------------------------------------------------------
+ case DW_OP_APPLE_error: // 0xFF - Stops expression evaluation and returns an error (no args)
+ if (error_ptr)
+ error_ptr->SetErrorString ("Generic error.");
+ return false;
+ }
+ }
+
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("Stack empty after evaluation.");
+ return false;
+ }
+ else if (log)
+ {
+ log->Printf("\n");
+ size_t count = stack.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ StreamString new_value;
+ new_value.Printf("[%zu]", i);
+ stack[i].Dump(&new_value);
+ log->Printf("%s", new_value.GetData());
+ }
+ }
+
+ result = stack.back();
+ return true; // Return true on success
+}
+
diff --git a/lldb/source/Expression/RecordingMemoryManager.cpp b/lldb/source/Expression/RecordingMemoryManager.cpp
new file mode 100644
index 00000000000..9f732b6c976
--- /dev/null
+++ b/lldb/source/Expression/RecordingMemoryManager.cpp
@@ -0,0 +1,131 @@
+//===-- RecordingMemoryManager.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define NO_RTTI
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Expression/RecordingMemoryManager.h"
+
+using namespace lldb_private;
+
+RecordingMemoryManager::RecordingMemoryManager () :
+ llvm::JITMemoryManager(),
+ m_default_mm_ap (llvm::JITMemoryManager::CreateDefaultMemManager())
+{
+}
+
+RecordingMemoryManager::~RecordingMemoryManager ()
+{
+}
+
+void
+RecordingMemoryManager::setMemoryWritable ()
+{
+ m_default_mm_ap->setMemoryWritable();
+}
+
+void
+RecordingMemoryManager::setMemoryExecutable ()
+{
+ m_default_mm_ap->setMemoryExecutable();
+}
+
+
+uint8_t *
+RecordingMemoryManager::startFunctionBody(const llvm::Function *F,
+ uintptr_t &ActualSize)
+{
+ uint8_t *return_value = m_default_mm_ap->startFunctionBody(F, ActualSize);
+ return return_value;
+}
+
+uint8_t *
+RecordingMemoryManager::allocateStub(const llvm::GlobalValue* F, unsigned StubSize,
+ unsigned Alignment)
+{
+ uint8_t *return_value = m_default_mm_ap->allocateStub(F, StubSize, Alignment);
+ m_stubs.insert (std::pair<uint8_t *,unsigned>(return_value, StubSize));
+ return return_value;
+}
+
+void
+RecordingMemoryManager::endFunctionBody(const llvm::Function *F, uint8_t *FunctionStart,
+ uint8_t *FunctionEnd)
+{
+ m_default_mm_ap->endFunctionBody(F, FunctionStart, FunctionEnd);
+ m_functions.insert(std::pair<uint8_t *, uint8_t *>(FunctionStart, FunctionEnd));
+}
+
+uint8_t *
+RecordingMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment)
+{
+ uint8_t *return_value = m_default_mm_ap->allocateSpace(Size, Alignment);
+ m_spaceBlocks.insert (std::pair<uint8_t *, intptr_t>(return_value, Size));
+ return return_value;
+}
+
+uint8_t *
+RecordingMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment)
+{
+ uint8_t *return_value = m_default_mm_ap->allocateGlobal(Size, Alignment);
+ m_globals.insert (std::pair<uint8_t *, uintptr_t>(return_value, Size));
+ return return_value;
+}
+
+void
+RecordingMemoryManager::deallocateFunctionBody(void *Body)
+{
+ m_default_mm_ap->deallocateFunctionBody(Body);
+}
+
+uint8_t*
+RecordingMemoryManager::startExceptionTable(const llvm::Function* F,
+ uintptr_t &ActualSize)
+{
+ uint8_t *return_value = m_default_mm_ap->startExceptionTable(F, ActualSize);
+ return return_value;
+}
+
+void
+RecordingMemoryManager::endExceptionTable(const llvm::Function *F, uint8_t *TableStart,
+ uint8_t *TableEnd, uint8_t* FrameRegister)
+{
+ m_default_mm_ap->endExceptionTable(F, TableStart, TableEnd, FrameRegister);
+ m_exception_tables.insert (std::pair<uint8_t *, uint8_t *>(TableStart, TableEnd));
+}
+
+void
+RecordingMemoryManager::deallocateExceptionTable(void *ET)
+{
+ m_default_mm_ap->deallocateExceptionTable (ET);
+}
+
+lldb::addr_t
+RecordingMemoryManager::GetRemoteAddressForLocal (lldb::addr_t local_address)
+{
+ std::vector<LocalToRemoteAddressRange>::iterator pos, end = m_address_map.end();
+ for (pos = m_address_map.begin(); pos < end; pos++)
+ {
+ lldb::addr_t lstart = (*pos).m_local_start;
+ if (local_address >= lstart && local_address < lstart + (*pos).m_size)
+ {
+ return (*pos).m_remote_start + (local_address - lstart);
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+void
+RecordingMemoryManager::AddToLocalToRemoteMap (lldb::addr_t lstart, size_t size, lldb::addr_t rstart)
+{
+ m_address_map.push_back (LocalToRemoteAddressRange(lstart, size, rstart));
+}
+
diff --git a/lldb/source/Host/macosx/Condition.cpp b/lldb/source/Host/macosx/Condition.cpp
new file mode 100644
index 00000000000..4e93db766db
--- /dev/null
+++ b/lldb/source/Host/macosx/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 owend 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 (pthread_mutex_t *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, &abstime_ts);
+ }
+ else
+ err = ::pthread_cond_wait (&m_condition, mutex);
+ } while (err == EINTR);
+
+ if (timed_out != NULL)
+ {
+ if (err == ETIMEDOUT)
+ *timed_out = true;
+ else
+ *timed_out = false;
+ }
+
+
+ return err;
+}
+
diff --git a/lldb/source/Host/macosx/Host.mm b/lldb/source/Host/macosx/Host.mm
new file mode 100644
index 00000000000..a18d45efe81
--- /dev/null
+++ b/lldb/source/Host/macosx/Host.mm
@@ -0,0 +1,803 @@
+//===-- Host.mm -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <dlfcn.h>
+#include <libgen.h>
+#include <mach/mach.h>
+#include <mach-o/dyld.h>
+#include <signal.h>
+#include <stddef.h>
+#include <sys/sysctl.h>
+#include <unistd.h>
+
+#include <map>
+#include <string>
+
+#include <objc/objc-auto.h>
+
+#include <Foundation/Foundation.h>
+
+#include "CFCBundle.h"
+#include "CFCReleaser.h"
+#include "CFCString.h"
+
+#include "lldb/Host/Host.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------
+// Return the size in bytes of a page on the host system
+//------------------------------------------------------------------
+size_t
+Host::GetPageSize()
+{
+ return ::getpagesize();
+}
+
+
+//------------------------------------------------------------------
+// Returns true if the host system is Big Endian.
+//------------------------------------------------------------------
+ByteOrder
+Host::GetByteOrder()
+{
+ union EndianTest
+ {
+ uint32_t num;
+ uint8_t bytes[sizeof(uint32_t)];
+ } endian = { (uint16_t)0x11223344 };
+ switch (endian.bytes[0])
+ {
+ case 0x11: return eByteOrderLittle;
+ case 0x44: return eByteOrderBig;
+ case 0x33: return eByteOrderPDP;
+ }
+ return eByteOrderInvalid;
+}
+
+lldb::pid_t
+Host::GetCurrentProcessID()
+{
+ return ::getpid();
+}
+
+lldb::pid_t
+Host::GetCurrentThreadID()
+{
+ return ::mach_thread_self();
+}
+
+
+const ArchSpec &
+Host::GetArchitecture ()
+{
+ static ArchSpec g_host_arch;
+ if (!g_host_arch.IsValid())
+ {
+ uint32_t cputype, cpusubtype;
+ uint32_t is_64_bit_capable;
+ size_t len = sizeof(cputype);
+ if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0)
+ {
+ len = sizeof(cpusubtype);
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
+ g_host_arch.SetArch(cputype, cpusubtype);
+
+ len = sizeof (is_64_bit_capable);
+ if (::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0) == 0)
+ {
+ if (is_64_bit_capable)
+ {
+ if (cputype == CPU_TYPE_I386 && cpusubtype == CPU_SUBTYPE_486)
+ cpusubtype = CPU_SUBTYPE_I386_ALL;
+
+ cputype |= CPU_ARCH_ABI64;
+ }
+ }
+ }
+ }
+ return g_host_arch;
+}
+
+const ConstString &
+Host::GetVendorString()
+{
+ static ConstString g_vendor;
+ if (!g_vendor)
+ {
+ char ostype[64];
+ size_t len = sizeof(ostype);
+ if (::sysctlbyname("kern.ostype", &ostype, &len, NULL, 0) == 0)
+ g_vendor.SetCString (ostype);
+ }
+ return g_vendor;
+}
+
+const ConstString &
+Host::GetOSString()
+{
+ static ConstString g_os_string("apple");
+ return g_os_string;
+}
+
+const ConstString &
+Host::GetTargetTriple()
+{
+ static ConstString g_host_triple;
+ if (!(g_host_triple))
+ {
+ StreamString triple;
+ triple.Printf("%s-%s-%s",
+ GetArchitecture ().AsCString(),
+ GetVendorString().AsCString("apple"),
+ GetOSString().AsCString("darwin"));
+
+ std::transform (triple.GetString().begin(),
+ triple.GetString().end(),
+ triple.GetString().begin(),
+ ::tolower);
+
+ g_host_triple.SetCString(triple.GetString().c_str());
+ }
+ return g_host_triple;
+}
+
+class MacOSXDarwinThread
+{
+public:
+ MacOSXDarwinThread(const char *thread_name) :
+ m_pool (nil)
+ {
+ // Register our thread with the collector if garbage collection is enabled.
+ if (objc_collectingEnabled())
+ {
+#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
+ // On Leopard and earlier there is no way objc_registerThreadWithCollector
+ // function, so we do it manually.
+ auto_zone_register_thread(auto_zone());
+#else
+ // On SnowLoepard and later we just call the thread registration function.
+ objc_registerThreadWithCollector();
+#endif
+ }
+ else
+ {
+ m_pool = [[NSAutoreleasePool alloc] init];
+ }
+
+
+ Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name);
+ }
+
+ ~MacOSXDarwinThread()
+ {
+ if (m_pool)
+ [m_pool release];
+ }
+
+ static void PThreadDestructor (void *v)
+ {
+ delete (MacOSXDarwinThread*)v;
+ }
+
+protected:
+ NSAutoreleasePool * m_pool;
+private:
+ DISALLOW_COPY_AND_ASSIGN (MacOSXDarwinThread);
+};
+
+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, MacOSXDarwinThread::PThreadDestructor);
+}
+
+typedef 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;
+}
+
+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 MacOSXDarwinThread(thread_name));
+ }
+}
+
+//------------------------------------------------------------------
+// Control access to a static file thread name map using a single
+// static function to avoid a static constructor.
+//------------------------------------------------------------------
+static const char *
+ThreadNameAccessor (bool get, lldb::pid_t pid, lldb::tid_t tid, const char *name)
+{
+
+ uint64_t pid_tid = ((uint64_t)pid << 32) | (uint64_t)tid;
+
+ static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
+ Mutex::Locker locker(&g_mutex);
+
+ typedef std::map<uint64_t, std::string> thread_name_map;
+ static thread_name_map g_thread_names;
+
+ if (get)
+ {
+ // See if the thread name exists in our thread name pool
+ thread_name_map::iterator pos = g_thread_names.find(pid_tid);
+ if (pos != g_thread_names.end())
+ return pos->second.c_str();
+ }
+ else
+ {
+ // Set the thread name
+ g_thread_names[pid_tid] = name;
+ }
+ return NULL;
+}
+
+
+
+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)
+ case SIGPOLL: return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported)
+#else // !_POSIX_C_SOURCE
+ case SIGEMT: return "SIGEMT"; // 7 EMT instruction
+#endif // !_POSIX_C_SOURCE
+ 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;
+}
+
+const char *
+Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid)
+{
+ const char *name = ThreadNameAccessor (true, pid, tid, NULL);
+ if (name == NULL)
+ {
+ // We currently can only get the name of a thread in the current process.
+#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
+ if (pid == Host::GetCurrentProcessID())
+ {
+ char pthread_name[1024];
+ if (::pthread_getname_np (::pthread_from_mach_thread_np (tid), pthread_name, sizeof(pthread_name)) == 0)
+ {
+ if (pthread_name[0])
+ {
+ // Set the thread in our string pool
+ ThreadNameAccessor (false, pid, tid, pthread_name);
+ // Get our copy of the thread name string
+ name = ThreadNameAccessor (true, pid, tid, NULL);
+ }
+ }
+ }
+#endif
+ }
+ return name;
+}
+
+void
+Host::SetThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name)
+{
+ 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 MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
+ // Set the pthread name if possible
+ if (pid == curr_pid && tid == curr_tid)
+ {
+ ::pthread_setname_np (name) == 0;
+ }
+#endif
+ ThreadNameAccessor (false, pid, tid, name);
+}
+
+FileSpec
+Host::GetProgramFileSpec ()
+{
+ static FileSpec g_program_filepsec;
+ if (!g_program_filepsec)
+ {
+ std::string program_fullpath;
+ program_fullpath.resize (PATH_MAX);
+ // If DST is NULL, then return the number of bytes needed.
+ uint32_t len = program_fullpath.size();
+ int err = _NSGetExecutablePath ((char *)program_fullpath.data(), &len);
+ if (err < 0)
+ {
+ // The path didn't fit in the buffer provided, increase its size
+ // and try again
+ program_fullpath.resize(len);
+ len = program_fullpath.size();
+ err = _NSGetExecutablePath ((char *)program_fullpath.data(), &len);
+ }
+ if (err == 0)
+ g_program_filepsec.SetFile(program_fullpath.data());
+ }
+ return g_program_filepsec;
+}
+
+
+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);
+ }
+ return module_filespec;
+}
+
+
+bool
+Host::ResolveExecutableInBundle (FileSpec *file)
+{
+ if (file->GetFileType () == FileSpec::eFileTypeDirectory)
+ {
+ char path[PATH_MAX];
+ if (file->GetPath(path, sizeof(path)))
+ {
+ CFCBundle bundle (path);
+ CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
+ if (url.get())
+ {
+ if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path)))
+ {
+ file->SetFile(path);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+typedef struct MonitorInfo
+{
+ int handle;
+ pthread_t thread;
+ Host::MonitorChildProcessCallback callback;
+ void *callback_baton;
+ bool monitor_signals;
+};
+
+typedef std::multimap<lldb::pid_t, MonitorInfo> MonitorInfoMap;
+static pthread_mutex_t g_monitor_map_mutex = PTHREAD_MUTEX_INITIALIZER;
+typedef lldb::SharedPtr<MonitorInfoMap>::Type MonitorInfoMapSP;
+
+static MonitorInfoMapSP&
+GetMonitorMap (bool can_create)
+{
+ static MonitorInfoMapSP g_monitor_map_sp;
+ if (can_create && g_monitor_map_sp.get() == NULL)
+ {
+ g_monitor_map_sp.reset (new MonitorInfoMap);
+ }
+ return g_monitor_map_sp;
+}
+
+static Predicate<bool>&
+GetChildProcessPredicate ()
+{
+ static Predicate<bool> g_has_child_processes;
+ return g_has_child_processes;
+}
+
+static void *
+MonitorChildProcessThreadFunction (void *arg);
+
+static pthread_t g_monitor_thread;
+
+uint32_t
+Host::StartMonitoringChildProcess
+(
+ MonitorChildProcessCallback callback,
+ void *callback_baton,
+ lldb::pid_t pid,
+ bool monitor_signals
+)
+{
+ static uint32_t g_handle = 0;
+ if (callback)
+ {
+ Mutex::Locker locker(&g_monitor_map_mutex);
+ if (!g_monitor_thread)
+ {
+ pid_t wait_pid = -1;
+ g_monitor_thread = ThreadCreate ("<lldb.host.wait4>",
+ MonitorChildProcessThreadFunction,
+ &wait_pid,
+ NULL);
+ if (g_monitor_thread)
+ {
+ //Host::ThreadDetach (g_monitor_thread, NULL);
+ }
+ }
+
+ if (g_monitor_thread)
+ {
+ MonitorInfo info = { ++g_handle, 0, callback, callback_baton, monitor_signals };
+ MonitorInfoMapSP monitor_map_sp (GetMonitorMap (true));
+ if (monitor_map_sp)
+ {
+ monitor_map_sp->insert(std::make_pair(pid, info));
+ GetChildProcessPredicate ().SetValue (true, eBroadcastOnChange);
+ return info.handle;
+ }
+ }
+ }
+ return 0;
+}
+
+bool
+Host::StopMonitoringChildProcess (uint32_t handle)
+{
+ Mutex::Locker locker(&g_monitor_map_mutex);
+ MonitorInfoMapSP monitor_map_sp (GetMonitorMap (false));
+ if (monitor_map_sp)
+ {
+ MonitorInfoMap::iterator pos, end = monitor_map_sp->end();
+ for (pos = monitor_map_sp->end(); pos != end; ++pos)
+ {
+ if (pos->second.handle == handle)
+ {
+ monitor_map_sp->erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+//------------------------------------------------------------------
+// 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);
+
+ const pid_t wait_pid = -1;//*((pid_t*)arg);
+ int status = -1;
+ const int options = 0;
+ struct rusage *rusage = NULL;
+ while (1)
+ {
+ if (log)
+ log->Printf("%s ::wait4 (pid = %i, &status, options = %i, rusage = %p)...", function, wait_pid, options, rusage);
+
+ // Wait for all child processes
+ ::pthread_testcancel ();
+ lldb::pid_t pid = ::wait4 (wait_pid, &status, options, rusage);
+ ::pthread_testcancel ();
+
+ if (pid < 0)
+ {
+ // No child processes to watch wait for the mutex to be cleared
+
+ // Scope for "locker"
+ {
+ ScopedPThreadCancelDisabler pthread_cancel_disabler;
+
+ // First clear out all monitor entries since we have no processes
+ // to watch.
+ Mutex::Locker locker(&g_monitor_map_mutex);
+ // Since we don't have any child processes, we can safely clear
+ // anyone with a valid pid.
+ MonitorInfoMapSP monitor_map_sp(GetMonitorMap (false));
+ if (monitor_map_sp)
+ {
+ MonitorInfoMap::iterator pos = monitor_map_sp->begin();
+ while (pos != monitor_map_sp->end())
+ {
+ // pid value of 0 and -1 are special (see man page on wait4...)
+ if (pos->first > 0)
+ {
+ MonitorInfoMap::iterator next_pos = pos; ++next_pos;
+ monitor_map_sp->erase (pos, next_pos);
+ pos = next_pos;
+ }
+ else
+ ++pos;
+ }
+ }
+ }
+
+ if (log)
+ log->Printf("%s no child processes, wait for some...", function);
+ GetChildProcessPredicate ().SetValue (false, eBroadcastNever);
+ ::pthread_testcancel();
+ GetChildProcessPredicate ().WaitForValueEqualTo (true);
+ if (log)
+ log->Printf("%s resuming monitoring of child processes.", function);
+
+ }
+ else
+ {
+ ScopedPThreadCancelDisabler pthread_cancel_disabler;
+ 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";
+ exited = true;
+ exit_status = -1;
+ }
+ else
+ {
+ status_cstr = "(???)";
+ }
+
+ if (log)
+ log->Printf ("%s ::wait4 (pid = %i, &status, options = %i, rusage = %p) => pid = %i, status = 0x%8.8x (%s), signal = %i, exit_state = %i",
+ function,
+ wait_pid,
+ options,
+ rusage,
+ pid,
+ status,
+ status_cstr,
+ signal,
+ exit_status);
+
+ // Scope for mutex locker
+ {
+ // Notify anyone listening to this process
+ Mutex::Locker locker(&g_monitor_map_mutex);
+ MonitorInfoMapSP monitor_map_sp(GetMonitorMap (false));
+ if (monitor_map_sp)
+ {
+ std::pair<MonitorInfoMap::iterator, MonitorInfoMap::iterator> range;
+ range = monitor_map_sp->equal_range(pid);
+ MonitorInfoMap::iterator pos;
+ for (pos = range.first; pos != range.second; ++pos)
+ {
+ if (exited || (signal != 0 && pos->second.monitor_signals))
+ {
+ bool callback_return = pos->second.callback (pos->second.callback_baton, pid, signal, exit_status);
+
+ if (exited || callback_return)
+ {
+ // Make this entry as needing to be removed by
+ // setting its handle to zero
+ pos->second.handle = 0;
+ }
+ }
+ }
+
+ // Remove any entries that requested to be removed or any
+ // entries for child processes that did exit. We know this
+ // because we changed the handles to an invalid value.
+ pos = monitor_map_sp->begin();
+ while (pos != monitor_map_sp->end())
+ {
+ if (pos->second.handle == 0)
+ {
+ MonitorInfoMap::iterator next_pos = pos; ++next_pos;
+ monitor_map_sp->erase (pos, next_pos);
+ pos = next_pos;
+ }
+ else
+ ++pos;
+ }
+ }
+ }
+ }
+ }
+
+ if (log)
+ log->Printf ("ProcessMacOSX::%s (arg = %p) thread exiting...", __FUNCTION__, arg);
+
+ g_monitor_thread = NULL;
+ return NULL;
+}
+
+void
+Host::WillTerminate ()
+{
+ if (g_monitor_thread != NULL)
+ {
+ ThreadCancel (g_monitor_thread, NULL);
+ GetChildProcessPredicate ().SetValue (true, eBroadcastAlways);
+ ThreadJoin(g_monitor_thread, NULL, NULL);
+ g_monitor_thread = NULL;
+ }
+}
+
diff --git a/lldb/source/Host/macosx/Mutex.cpp b/lldb/source/Host/macosx/Mutex.cpp
new file mode 100644
index 00000000000..ab0b67aa051
--- /dev/null
+++ b/lldb/source/Host/macosx/Mutex.cpp
@@ -0,0 +1,244 @@
+//===-- 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/Core/Log.h"
+
+#if 0
+#include "lldb/Host/Host.h"
+#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_LOG(fmt, ...)
+#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(m.GetMutex())
+{
+ if (m_mutex_ptr)
+ Mutex::Lock (m_mutex_ptr);
+}
+
+//----------------------------------------------------------------------
+// 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(m ? m->GetMutex() : NULL)
+{
+ if (m_mutex_ptr)
+ Mutex::Lock (m_mutex_ptr);
+}
+
+//----------------------------------------------------------------------
+// Constructor with a raw pthread mutex object pointer.
+//
+// This will create a scoped mutex locking object that locks "mutex"
+//----------------------------------------------------------------------
+Mutex::Locker::Locker (pthread_mutex_t *mutex_ptr) :
+ m_mutex_ptr(mutex_ptr)
+{
+ if (m_mutex_ptr)
+ Mutex::Lock (m_mutex_ptr);
+}
+
+//----------------------------------------------------------------------
+// Desstructor
+//
+// Unlocks any owned mutex object (if it is valid).
+//----------------------------------------------------------------------
+Mutex::Locker::~Locker ()
+{
+ if (m_mutex_ptr)
+ Mutex::Unlock (m_mutex_ptr);
+}
+
+//----------------------------------------------------------------------
+// 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::Reset (pthread_mutex_t *mutex_ptr)
+{
+ if (m_mutex_ptr)
+ Mutex::Unlock (m_mutex_ptr);
+
+ m_mutex_ptr = mutex_ptr;
+ if (m_mutex_ptr)
+ Mutex::Lock (m_mutex_ptr);
+}
+
+bool
+Mutex::Locker::TryLock (pthread_mutex_t *mutex_ptr)
+{
+ if (m_mutex_ptr)
+ Mutex::Unlock (m_mutex_ptr);
+ m_mutex_ptr = NULL;
+ if (mutex_ptr)
+ {
+ if (Mutex::TryLock (mutex_ptr) == 0)
+ m_mutex_ptr = mutex_ptr;
+ }
+ 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);
+ 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:
+ err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL);
+ break;
+
+ case eMutexTypeRecursive:
+ err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
+ break;
+
+ default:
+ err = -1;
+ break;
+ }
+ assert(err == 0);
+ err = ::pthread_mutex_init (&m_mutex, &attr);
+ assert(err == 0);
+ err = ::pthread_mutexattr_destroy (&attr);
+ assert(err == 0);
+}
+
+//----------------------------------------------------------------------
+// Destructor.
+//
+// Destroys the mutex owned by this object.
+//----------------------------------------------------------------------
+Mutex::~Mutex()
+{
+ int err;
+ err = ::pthread_mutex_destroy (&m_mutex);
+}
+
+//----------------------------------------------------------------------
+// Mutex get accessor.
+//----------------------------------------------------------------------
+pthread_mutex_t *
+Mutex::GetMutex()
+{
+ return &m_mutex;
+}
+
+int
+Mutex::Lock (pthread_mutex_t *mutex_ptr)
+{
+ DEBUG_LOG ("[%4.4x/%4.4x] pthread_mutex_lock (%p)...\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), mutex_ptr);
+ int err = ::pthread_mutex_lock (mutex_ptr);
+ DEBUG_LOG ("[%4.4x/%4.4x] pthread_mutex_lock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), mutex_ptr, err);
+ return err;
+}
+
+int
+Mutex::TryLock (pthread_mutex_t *mutex_ptr)
+{
+ int err = ::pthread_mutex_trylock (mutex_ptr);
+ DEBUG_LOG ("[%4.4x/%4.4x] pthread_mutex_trylock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), mutex_ptr, err);
+ return err;
+}
+
+int
+Mutex::Unlock (pthread_mutex_t *mutex_ptr)
+{
+ int err = ::pthread_mutex_unlock (mutex_ptr);
+ DEBUG_LOG ("[%4.4x/%4.4x] pthread_mutex_unlock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), mutex_ptr, err);
+ return err;
+}
+
+//----------------------------------------------------------------------
+// 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()
+{
+ return Mutex::Lock (&m_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.
+//
+// RETURNS
+// The error code from the pthread_mutex_trylock() function call.
+//----------------------------------------------------------------------
+int
+Mutex::TryLock()
+{
+ return Mutex::TryLock (&m_mutex);
+}
+
+//----------------------------------------------------------------------
+// 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()
+{
+ return Mutex::Unlock (&m_mutex);
+}
diff --git a/lldb/source/Host/macosx/Symbols.cpp b/lldb/source/Host/macosx/Symbols.cpp
new file mode 100644
index 00000000000..ff28157258b
--- /dev/null
+++ b/lldb/source/Host/macosx/Symbols.cpp
@@ -0,0 +1,462 @@
+//===-- 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"
+
+// C Includes
+#include <dirent.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include <CoreFoundation/CoreFoundation.h>
+
+// Project includes
+#include "CFCReleaser.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/UUID.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+extern "C" {
+CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url);
+CFDictionaryRef DBGCopyDSYMPropertyLists (CFURLRef dsym_url);
+};
+
+static bool
+SkinnyMachOFileContainsArchAndUUID
+(
+ const FileSpec &file_spec,
+ const ArchSpec *arch,
+ const UUID *uuid, // the UUID we are looking for
+ off_t file_offset,
+ DataExtractor& data,
+ uint32_t data_offset,
+ const uint32_t magic
+)
+{
+ assert(magic == MH_CIGAM || magic == MH_MAGIC || magic == MH_CIGAM_64 || magic == MH_MAGIC_64);
+ if (magic == MH_MAGIC || magic == MH_MAGIC_64)
+ data.SetByteOrder (eByteOrderHost);
+ else if (eByteOrderHost == eByteOrderBig)
+ data.SetByteOrder (eByteOrderLittle);
+ else
+ data.SetByteOrder (eByteOrderBig);
+
+ uint32_t i;
+ const uint32_t cputype = data.GetU32(&data_offset); // cpu specifier
+ const uint32_t cpusubtype = data.GetU32(&data_offset); // machine specifier
+ data_offset+=4; // Skip mach file type
+ const uint32_t ncmds = data.GetU32(&data_offset); // number of load commands
+ const uint32_t sizeofcmds = data.GetU32(&data_offset); // the size of all the load commands
+ data_offset+=4; // Skip flags
+
+ // Check the architecture if we have a valid arch pointer
+ if (arch)
+ {
+ ArchSpec file_arch(cputype, cpusubtype);
+
+ if (file_arch != *arch)
+ return false;
+ }
+
+ // The file exists, and if a valid arch pointer was passed in we know
+ // if already matches, so we can return if we aren't looking for a specific
+ // UUID
+ if (uuid == NULL)
+ return true;
+
+ if (magic == MH_CIGAM_64 || magic == MH_MAGIC_64)
+ data_offset += 4; // Skip reserved field for in mach_header_64
+
+ // Make sure we have enough data for all the load commands
+ if (magic == MH_CIGAM_64 || magic == MH_MAGIC_64)
+ {
+ if (data.GetByteSize() < sizeof(struct mach_header_64) + sizeofcmds)
+ {
+ DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, sizeof(struct mach_header_64) + sizeofcmds));
+ data.SetData (data_buffer_sp);
+ }
+ }
+ else
+ {
+ if (data.GetByteSize() < sizeof(struct mach_header) + sizeofcmds)
+ {
+ DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, sizeof(struct mach_header) + sizeofcmds));
+ data.SetData (data_buffer_sp);
+ }
+ }
+
+ for (i=0; i<ncmds; i++)
+ {
+ const uint32_t cmd_offset = data_offset; // Save this data_offset in case parsing of the segment goes awry!
+ uint32_t cmd = data.GetU32(&data_offset);
+ uint32_t cmd_size = data.GetU32(&data_offset);
+ if (cmd == LC_UUID)
+ {
+ UUID file_uuid (data.GetData(&data_offset, 16), 16);
+ return file_uuid == *uuid;
+ }
+ data_offset = cmd_offset + cmd_size;
+ }
+ return false;
+}
+
+bool
+UniversalMachOFileContainsArchAndUUID
+(
+ const FileSpec &file_spec,
+ const ArchSpec *arch,
+ const UUID *uuid,
+ off_t file_offset,
+ DataExtractor& data,
+ uint32_t data_offset,
+ const uint32_t magic
+)
+{
+ assert(magic == FAT_CIGAM || magic == FAT_MAGIC);
+
+ // Universal mach-o files always have their headers encoded as BIG endian
+ data.SetByteOrder(eByteOrderBig);
+
+ uint32_t i;
+ const uint32_t nfat_arch = data.GetU32(&data_offset); // number of structs that follow
+ const uint32_t fat_header_and_arch_size = sizeof(struct fat_header) + nfat_arch * sizeof(struct fat_arch);
+ if (data.GetByteSize() < fat_header_and_arch_size)
+ {
+ DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, fat_header_and_arch_size));
+ data.SetData (data_buffer_sp);
+ }
+
+ for (i=0; i<nfat_arch; i++)
+ {
+ cpu_type_t arch_cputype = data.GetU32(&data_offset); // cpu specifier (int)
+ cpu_subtype_t arch_cpusubtype = data.GetU32(&data_offset); // machine specifier (int)
+ uint32_t arch_offset = data.GetU32(&data_offset); // file offset to this object file
+ // uint32_t arch_size = data.GetU32(&data_offset); // size of this object file
+ // uint32_t arch_align = data.GetU32(&data_offset); // alignment as a power of 2
+ data_offset += 8; // Skip size and align as we don't need those
+ // Only process this slice if the cpu type/subtype matches
+ if (arch)
+ {
+ ArchSpec fat_arch(arch_cputype, arch_cpusubtype);
+ if (fat_arch != *arch)
+ continue;
+ }
+
+ // Create a buffer with only the arch slice date in it
+ DataExtractor arch_data;
+ DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset + arch_offset, 0x1000));
+ arch_data.SetData(data_buffer_sp);
+ uint32_t arch_data_offset = 0;
+ uint32_t arch_magic = arch_data.GetU32(&arch_data_offset);
+
+ switch (arch_magic)
+ {
+ case MH_CIGAM: // 32 bit mach-o file
+ case MH_MAGIC: // 32 bit mach-o file
+ case MH_CIGAM_64: // 64 bit mach-o file
+ case MH_MAGIC_64: // 64 bit mach-o file
+ if (SkinnyMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset + arch_offset, arch_data, arch_data_offset, arch_magic))
+ return true;
+ break;
+ }
+ }
+ return false;
+}
+
+static bool
+FileAtPathContainsArchAndUUID
+(
+ const FileSpec &file_spec,
+ const ArchSpec *arch,
+ const UUID *uuid
+)
+{
+ DataExtractor data;
+ off_t file_offset = 0;
+ DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, 0x1000));
+
+ if (data_buffer_sp && data_buffer_sp->GetByteSize() > 0)
+ {
+ data.SetData(data_buffer_sp);
+
+ uint32_t data_offset = 0;
+ uint32_t magic = data.GetU32(&data_offset);
+
+ switch (magic)
+ {
+ // 32 bit mach-o file
+ case MH_CIGAM:
+ case MH_MAGIC:
+ case MH_CIGAM_64:
+ case MH_MAGIC_64:
+ return SkinnyMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset, data, data_offset, magic);
+
+ // fat mach-o file
+ case FAT_CIGAM:
+ case FAT_MAGIC:
+ return UniversalMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset, data, data_offset, magic);
+
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+static FileSpec
+LocateDSYMMachFileInDSYMBundle
+(
+ const FileSpec& dsym_bundle_fspec,
+ const UUID *uuid,
+ const ArchSpec *arch)
+{
+ char path[PATH_MAX];
+
+ FileSpec dsym_fspec;
+
+ if (dsym_bundle_fspec.GetPath(path, sizeof(path)))
+ {
+ ::strncat (path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1);
+
+ DIR* dirp = ::opendir(path);
+ if (dirp != NULL)
+ {
+ const size_t path_len = strlen(path);
+ const int bytes_left = sizeof(path) - path_len - 1;
+ struct dirent* dp;
+ while ((dp = readdir(dirp)) != NULL)
+ {
+ // Only search directories
+ if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
+ {
+ if (dp->d_namlen == 1 && dp->d_name[0] == '.')
+ continue;
+
+ if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
+ continue;
+ }
+
+ if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN)
+ {
+ ::strncpy (&path[path_len], dp->d_name, bytes_left);
+
+ dsym_fspec.SetFile(path);
+ if (FileAtPathContainsArchAndUUID (dsym_fspec, arch, uuid))
+ return dsym_fspec;
+ }
+ }
+ }
+ }
+ dsym_fspec.Clear();
+ return dsym_fspec;
+}
+
+static int
+LocateMacOSXFilesUsingDebugSymbols
+(
+ const FileSpec *exec_fspec, // An executable path that may or may not be correct if UUID is specified
+ const ArchSpec* arch, // Limit the search to files with this architecture if non-NULL
+ const UUID *uuid, // Match the UUID value if non-NULL,
+ FileSpec *out_exec_fspec, // If non-NULL, try and find the executable
+ FileSpec *out_dsym_fspec // If non-NULL try and find the debug symbol file
+)
+{
+ int items_found = 0;
+
+ if (out_exec_fspec)
+ out_exec_fspec->Clear();
+
+ if (out_dsym_fspec)
+ out_dsym_fspec->Clear();
+
+ if (uuid && uuid->IsValid())
+ {
+ // Try and locate the dSYM file using DebugSymbols first
+ const UInt8 *module_uuid = (const UInt8 *)uuid->GetBytes();
+ if (module_uuid != NULL)
+ {
+ CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes ( NULL,
+ module_uuid[0],
+ module_uuid[1],
+ module_uuid[2],
+ module_uuid[3],
+ module_uuid[4],
+ module_uuid[5],
+ module_uuid[6],
+ module_uuid[7],
+ module_uuid[8],
+ module_uuid[9],
+ module_uuid[10],
+ module_uuid[11],
+ module_uuid[12],
+ module_uuid[13],
+ module_uuid[14],
+ module_uuid[15]));
+
+ if (module_uuid_ref.get())
+ {
+ CFCReleaser<CFURLRef> exec_url;
+
+ if (exec_fspec)
+ {
+ char exec_cf_path[PATH_MAX];
+ if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
+ exec_url.reset(::CFURLCreateFromFileSystemRepresentation (NULL,
+ (const UInt8 *)exec_cf_path,
+ strlen(exec_cf_path),
+ FALSE));
+ }
+
+ CFCReleaser<CFURLRef> dsym_url (::DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get()));
+ char path[PATH_MAX];
+
+ if (dsym_url.get())
+ {
+ if (out_dsym_fspec)
+ {
+ if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
+ {
+ out_dsym_fspec->SetFile(path);
+
+ if (out_dsym_fspec->GetFileType () == FileSpec::eFileTypeDirectory)
+ {
+ *out_dsym_fspec = LocateDSYMMachFileInDSYMBundle (*out_dsym_fspec, uuid, arch);
+ if (*out_dsym_fspec)
+ ++items_found;
+ }
+ else
+ {
+ ++items_found;
+ }
+ }
+ }
+
+ if (out_exec_fspec)
+ {
+ CFCReleaser<CFDictionaryRef> dict(::DBGCopyDSYMPropertyLists (dsym_url.get()));;
+ if (dict.get())
+ {
+ CFStringRef exec_cf_path = static_cast<CFStringRef>(::CFDictionaryGetValue (dict.get(), CFSTR("DBGSymbolRichExecutable")));
+ if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path)))
+ {
+ ++items_found;
+ out_dsym_fspec->SetFile(path);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return items_found;
+}
+
+static bool
+LocateDSYMInVincinityOfExecutable (const FileSpec *exec_fspec, const ArchSpec* arch, const UUID *uuid, FileSpec &dsym_fspec)
+{
+ if (exec_fspec)
+ {
+ char path[PATH_MAX];
+ if (exec_fspec->GetPath(path, sizeof(path)))
+ {
+ // Make sure the module isn't already just a dSYM file...
+ if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL)
+ {
+ size_t obj_file_path_length = strlen(path);
+ strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path));
+ strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path));
+
+ dsym_fspec.SetFile(path);
+
+ if (FileAtPathContainsArchAndUUID (dsym_fspec, arch, uuid))
+ {
+ return true;
+ }
+ else
+ {
+ path[obj_file_path_length] = '\0';
+
+ char *last_dot = strrchr(path, '.');
+ while (last_dot != NULL && last_dot[0])
+ {
+ char *next_slash = strchr(last_dot, '/');
+ if (next_slash != NULL)
+ {
+ *next_slash = '\0';
+ strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path));
+ strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path));
+ dsym_fspec.SetFile(path);
+ if (dsym_fspec.Exists())
+ return true;
+ else
+ {
+ *last_dot = '\0';
+ char *prev_slash = strrchr(path, '/');
+ if (prev_slash != NULL)
+ *prev_slash = '\0';
+ else
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ dsym_fspec.Clear();
+ return false;
+}
+
+FileSpec
+Symbols::LocateExecutableObjectFile (const FileSpec *exec_fspec, const ArchSpec* arch, const UUID *uuid)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
+ exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
+ arch ? arch->AsCString() : "<NULL>",
+ uuid);
+
+ FileSpec objfile_fspec;
+ if (exec_fspec && FileAtPathContainsArchAndUUID (*exec_fspec, arch, uuid))
+ objfile_fspec = *exec_fspec;
+ else
+ LocateMacOSXFilesUsingDebugSymbols (exec_fspec, arch, uuid, &objfile_fspec, NULL);
+ return objfile_fspec;
+}
+
+FileSpec
+Symbols::LocateExecutableSymbolFile (const FileSpec *exec_fspec, const ArchSpec* arch, const UUID *uuid)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "LocateExecutableSymbolFile (file = %s, arch = %s, uuid = %p)",
+ exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
+ arch ? arch->AsCString() : "<NULL>",
+ uuid);
+
+ FileSpec symbol_fspec;
+ // First try and find the dSYM in the same directory as the executable or in
+ // an appropriate parent directory
+ if (LocateDSYMInVincinityOfExecutable (exec_fspec, arch, uuid, symbol_fspec) == false)
+ {
+ // We failed to easily find the dSYM above, so use DebugSymbols
+ LocateMacOSXFilesUsingDebugSymbols (exec_fspec, arch, uuid, NULL, &symbol_fspec);
+ }
+ return symbol_fspec;
+}
diff --git a/lldb/source/Host/macosx/TimeValue.cpp b/lldb/source/Host/macosx/TimeValue.cpp
new file mode 100644
index 00000000000..27aad5f7bc7
--- /dev/null
+++ b/lldb/source/Host/macosx/TimeValue.cpp
@@ -0,0 +1,179 @@
+//===-- 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 "TimeValue.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#define NSEC_PER_USEC 1000ull
+#define USEC_PER_SEC 1000000ull
+#define NSEC_PER_SEC 1000000000ull
+
+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 (ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec)
+{
+}
+
+TimeValue::TimeValue(const struct timeval& tv) :
+ m_nano_seconds (tv.tv_sec * NSEC_PER_SEC + tv.tv_usec * NSEC_PER_USEC)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+TimeValue::~TimeValue()
+{
+}
+
+
+uint64_t
+TimeValue::GetAsNanoSecondsSinceJan1_1970() const
+{
+ return m_nano_seconds;
+}
+
+uint64_t
+TimeValue::GetAsMicroSecondsSinceJan1_1970() const
+{
+ return m_nano_seconds / NSEC_PER_USEC;
+}
+
+struct timespec
+TimeValue::GetAsTimeSpec () const
+{
+ struct timespec ts;
+ ts.tv_sec = m_nano_seconds / NSEC_PER_SEC;
+ ts.tv_nsec = m_nano_seconds % NSEC_PER_SEC;
+ return ts;
+}
+
+struct timeval
+TimeValue::GetAsTimeVal () const
+{
+ struct timeval tv;
+ tv.tv_sec = m_nano_seconds / NSEC_PER_SEC;
+ tv.tv_usec = (m_nano_seconds % NSEC_PER_SEC) / NSEC_PER_USEC;
+ return tv;
+}
+
+void
+TimeValue::Clear ()
+{
+ m_nano_seconds = 0;
+}
+
+bool
+TimeValue::IsValid () const
+{
+ return m_nano_seconds != 0;
+}
+
+void
+TimeValue::OffsetWithSeconds (uint32_t sec)
+{
+ m_nano_seconds += sec * NSEC_PER_SEC;
+}
+
+void
+TimeValue::OffsetWithMicroSeconds (uint32_t usec)
+{
+ m_nano_seconds += usec * NSEC_PER_USEC;
+}
+
+void
+TimeValue::OffsetWithNanoSeconds (uint32_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;
+}
+
+
+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/lldb/source/Host/macosx/cfcpp/CFCBundle.cpp b/lldb/source/Host/macosx/cfcpp/CFCBundle.cpp
new file mode 100644
index 00000000000..6e68af5c597
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCBundle.cpp
@@ -0,0 +1,83 @@
+//===-- CFCBundle.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCBundle.h"
+#include "CFCString.h"
+
+//----------------------------------------------------------------------
+// CFCBundle constructor
+//----------------------------------------------------------------------
+CFCBundle::CFCBundle(const char *path) :
+ CFCReleaser<CFBundleRef>()
+{
+ if (path && path[0])
+ SetPath(path);
+}
+
+CFCBundle::CFCBundle(CFURLRef url) :
+ CFCReleaser<CFBundleRef>(url ? CFBundleCreate(NULL, url) : NULL)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCBundle::~CFCBundle()
+{
+}
+
+//----------------------------------------------------------------------
+// Set the path for a bundle by supplying a
+//----------------------------------------------------------------------
+bool
+CFCBundle::SetPath (const char *path)
+{
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+ // Release our old bundle and URL
+ reset();
+
+ // Make a CFStringRef from the supplied path
+ CFCString cf_path;
+ cf_path.SetFileSystemRepresentation(path);
+ if (cf_path.get())
+ {
+ // Make our Bundle URL
+ CFCReleaser<CFURLRef> bundle_url (::CFURLCreateWithFileSystemPath (alloc, cf_path.get(), kCFURLPOSIXPathStyle, true));
+ if (bundle_url.get())
+ reset (::CFBundleCreate (alloc, bundle_url.get()));
+ }
+ return get() != NULL;
+}
+
+CFStringRef
+CFCBundle::GetIdentifier () const
+{
+ CFBundleRef bundle = get();
+ if (bundle != NULL)
+ return ::CFBundleGetIdentifier (bundle);
+ return NULL;
+}
+
+CFTypeRef
+CFCBundle::GetValueForInfoDictionaryKey(CFStringRef key) const
+{
+ CFBundleRef bundle = get();
+ if (bundle != NULL)
+ return ::CFBundleGetValueForInfoDictionaryKey(bundle, key);
+ return NULL;
+}
+
+CFURLRef
+CFCBundle::CopyExecutableURL () const
+{
+ CFBundleRef bundle = get();
+ if (bundle != NULL)
+ return CFBundleCopyExecutableURL(bundle);
+ return NULL;
+}
diff --git a/lldb/source/Host/macosx/cfcpp/CFCBundle.h b/lldb/source/Host/macosx/cfcpp/CFCBundle.h
new file mode 100644
index 00000000000..c07a48cb055
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCBundle.h
@@ -0,0 +1,47 @@
+//===-- CFCBundle.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFBundle_h_
+#define CoreFoundationCPP_CFBundle_h_
+
+#include "CFCReleaser.h"
+
+class CFCBundle : public CFCReleaser<CFBundleRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCBundle (const char *path = NULL);
+ CFCBundle (CFURLRef url);
+
+ virtual
+ ~CFCBundle();
+
+ CFURLRef
+ CopyExecutableURL () const;
+
+ CFStringRef
+ GetIdentifier () const;
+
+ CFTypeRef
+ GetValueForInfoDictionaryKey(CFStringRef key) const;
+
+ bool
+ SetPath (const char *path);
+
+private:
+ // Disallow copy and assignment constructors
+ CFCBundle(const CFCBundle&);
+
+ const CFCBundle&
+ operator=(const CFCBundle&);
+};
+
+#endif // #ifndef CoreFoundationCPP_CFBundle_h_
diff --git a/lldb/source/Host/macosx/cfcpp/CFCData.cpp b/lldb/source/Host/macosx/cfcpp/CFCData.cpp
new file mode 100644
index 00000000000..4f49368ad8a
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCData.cpp
@@ -0,0 +1,82 @@
+//===-- CFCData.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCData.h"
+
+//----------------------------------------------------------------------
+// CFCData constructor
+//----------------------------------------------------------------------
+CFCData::CFCData(CFDataRef data) :
+ CFCReleaser<CFDataRef>(data)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFCData copy constructor
+//----------------------------------------------------------------------
+CFCData::CFCData(const CFCData& rhs) :
+ CFCReleaser<CFDataRef>(rhs)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFCData copy constructor
+//----------------------------------------------------------------------
+CFCData&
+CFCData::operator=(const CFCData& rhs)
+
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCData::~CFCData()
+{
+}
+
+
+CFIndex
+CFCData::GetLength() const
+{
+ CFDataRef data = get();
+ if (data)
+ return CFDataGetLength (data);
+ return 0;
+}
+
+
+const uint8_t*
+CFCData::GetBytePtr() const
+{
+ CFDataRef data = get();
+ if (data)
+ return CFDataGetBytePtr (data);
+ return NULL;
+}
+
+CFDataRef
+CFCData::Serialize(CFPropertyListRef plist, CFPropertyListFormat format)
+{
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+ reset();
+ CFCReleaser<CFWriteStreamRef> stream (::CFWriteStreamCreateWithAllocatedBuffers (alloc, alloc));
+ ::CFWriteStreamOpen (stream.get());
+ CFIndex len = ::CFPropertyListWriteToStream (plist, stream.get(), format, NULL);
+ if (len > 0)
+ reset((CFDataRef)::CFWriteStreamCopyProperty (stream.get(), kCFStreamPropertyDataWritten));
+ ::CFWriteStreamClose (stream.get());
+ return get();
+}
+
diff --git a/lldb/source/Host/macosx/cfcpp/CFCData.h b/lldb/source/Host/macosx/cfcpp/CFCData.h
new file mode 100644
index 00000000000..6a718f54c05
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCData.h
@@ -0,0 +1,35 @@
+//===-- CFCData.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFData_h_
+#define CoreFoundationCPP_CFData_h_
+
+#include "CFCReleaser.h"
+
+class CFCData : public CFCReleaser<CFDataRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCData(CFDataRef data = NULL);
+ CFCData(const CFCData& rhs);
+ CFCData& operator=(const CFCData& rhs);
+ virtual ~CFCData();
+
+ CFDataRef Serialize(CFPropertyListRef plist, CFPropertyListFormat format);
+ const uint8_t* GetBytePtr () const;
+ CFIndex GetLength () const;
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from CFCData can see and modify these
+ //------------------------------------------------------------------
+};
+
+#endif // #ifndef CoreFoundationCPP_CFData_h_
diff --git a/lldb/source/Host/macosx/cfcpp/CFCMutableArray.cpp b/lldb/source/Host/macosx/cfcpp/CFCMutableArray.cpp
new file mode 100644
index 00000000000..3b92f03fa61
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCMutableArray.cpp
@@ -0,0 +1,123 @@
+//===-- CFCMutableArray.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCMutableArray.h"
+
+//----------------------------------------------------------------------
+// CFCString constructor
+//----------------------------------------------------------------------
+CFCMutableArray::CFCMutableArray(CFMutableArrayRef s) :
+ CFCReleaser<CFMutableArrayRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableArray copy constructor
+//----------------------------------------------------------------------
+CFCMutableArray::CFCMutableArray(const CFCMutableArray& rhs) :
+ CFCReleaser<CFMutableArrayRef> (rhs) // NOTE: this won't make a copy of the array, just add a new reference to it
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableArray copy constructor
+//----------------------------------------------------------------------
+CFCMutableArray&
+CFCMutableArray::operator=(const CFCMutableArray& rhs)
+{
+ if (this != &rhs)
+ *this = rhs; // NOTE: this operator won't make a copy of the array, just add a new reference to it
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCMutableArray::~CFCMutableArray()
+{
+}
+
+
+CFIndex
+CFCMutableArray::GetCount() const
+{
+ CFMutableArrayRef array = get();
+ if (array)
+ return ::CFArrayGetCount (array);
+ return 0;
+}
+
+CFIndex
+CFCMutableArray::GetCountOfValue(CFRange range, const void *value) const
+{
+ CFMutableArrayRef array = get();
+ if (array)
+ return ::CFArrayGetCountOfValue (array, range, value);
+ return 0;
+}
+
+CFIndex
+CFCMutableArray::GetCountOfValue(const void *value) const
+{
+ CFMutableArrayRef array = get();
+ if (array)
+ return ::CFArrayGetCountOfValue (array, CFRangeMake(0, GetCount()), value);
+ return 0;
+}
+
+const void *
+CFCMutableArray::GetValueAtIndex(CFIndex idx) const
+{
+ CFMutableArrayRef array = get();
+ if (array)
+ {
+ const CFIndex num_array_items = ::CFArrayGetCount (array);
+ if (0 <= idx && idx < num_array_items)
+ {
+ return ::CFArrayGetValueAtIndex (array, idx);
+ }
+ }
+ return NULL;
+}
+
+bool
+CFCMutableArray::SetValueAtIndex(CFIndex idx, const void *value)
+{
+ CFMutableArrayRef array = get();
+ if (array != NULL)
+ {
+ const CFIndex num_array_items = ::CFArrayGetCount (array);
+ if (0 <= idx && idx < num_array_items)
+ {
+ ::CFArraySetValueAtIndex (array, idx, value);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CFCMutableArray::AppendValue(const void *value, bool can_create)
+{
+ CFMutableArrayRef array = get();
+ if (array == NULL)
+ {
+ if (can_create == false)
+ return false;
+ array = ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ reset ( array );
+ }
+ if (array != NULL)
+ {
+ ::CFArrayAppendValue(array, value);
+ return true;
+ }
+ return false;
+}
diff --git a/lldb/source/Host/macosx/cfcpp/CFCMutableArray.h b/lldb/source/Host/macosx/cfcpp/CFCMutableArray.h
new file mode 100644
index 00000000000..eaadb8d5590
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCMutableArray.h
@@ -0,0 +1,34 @@
+//===-- CFCMutableArray.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFMutableArray_h_
+#define CoreFoundationCPP_CFMutableArray_h_
+
+#include "CFCReleaser.h"
+
+class CFCMutableArray : public CFCReleaser<CFMutableArrayRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCMutableArray(CFMutableArrayRef array = NULL);
+ CFCMutableArray(const CFCMutableArray& rhs); // This will copy the array contents into a new array
+ CFCMutableArray& operator=(const CFCMutableArray& rhs); // This will re-use the same array and just bump the ref count
+ virtual ~CFCMutableArray();
+
+ CFIndex GetCount() const;
+ CFIndex GetCountOfValue(const void *value) const;
+ CFIndex GetCountOfValue(CFRange range, const void *value) const;
+ const void * GetValueAtIndex(CFIndex idx) const;
+ bool SetValueAtIndex(CFIndex idx, const void *value);
+ bool AppendValue(const void *value, bool can_create = true); // Appends value and optionally creates a CFCMutableArray if this class doesn't contain one
+};
+
+#endif // #ifndef CoreFoundationCPP_CFMutableArray_h_
diff --git a/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp b/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp
new file mode 100644
index 00000000000..963221adb4a
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp
@@ -0,0 +1,491 @@
+//===-- CFCMutableDictionary.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCMutableDictionary.h"
+#include "CFCString.h"
+//----------------------------------------------------------------------
+// CFCString constructor
+//----------------------------------------------------------------------
+CFCMutableDictionary::CFCMutableDictionary(CFMutableDictionaryRef s) :
+ CFCReleaser<CFMutableDictionaryRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableDictionary copy constructor
+//----------------------------------------------------------------------
+CFCMutableDictionary::CFCMutableDictionary(const CFCMutableDictionary& rhs) :
+ CFCReleaser<CFMutableDictionaryRef> (rhs)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableDictionary copy constructor
+//----------------------------------------------------------------------
+const CFCMutableDictionary&
+CFCMutableDictionary::operator=(const CFCMutableDictionary& rhs)
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCMutableDictionary::~CFCMutableDictionary()
+{
+}
+
+
+CFIndex
+CFCMutableDictionary::GetCount() const
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetCount (dict);
+ return 0;
+}
+
+CFIndex
+CFCMutableDictionary::GetCountOfKey(const void *key) const
+
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetCountOfKey (dict, key);
+ return 0;
+}
+
+CFIndex
+CFCMutableDictionary::GetCountOfValue(const void *value) const
+
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetCountOfValue (dict, value);
+ return 0;
+}
+
+void
+CFCMutableDictionary::GetKeysAndValues(const void **keys, const void **values) const
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ ::CFDictionaryGetKeysAndValues (dict, keys, values);
+}
+
+
+const void *
+CFCMutableDictionary::GetValue(const void *key) const
+
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetValue (dict, key);
+ return NULL;
+}
+
+Boolean
+CFCMutableDictionary::GetValueIfPresent(const void *key, const void **value_handle) const
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetValueIfPresent (dict, key, value_handle);
+ return false;
+}
+
+
+CFMutableDictionaryRef
+CFCMutableDictionary::Dictionary(bool can_create)
+{
+ CFMutableDictionaryRef dict = get();
+ if (can_create && dict == NULL)
+ {
+ dict = ::CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ reset ( dict );
+ }
+ return dict;
+}
+
+bool
+CFCMutableDictionary::AddValue(CFStringRef key, const void *value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValue(CFStringRef key, const void *value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueSInt8(CFStringRef key, int8_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt8Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueSInt8(CFStringRef key, int8_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt8Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueSInt16(CFStringRef key, int16_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt16Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueSInt16(CFStringRef key, int16_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt16Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueSInt32(CFStringRef key, int32_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueSInt32(CFStringRef key, int32_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueSInt64(CFStringRef key, int64_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueSInt64(CFStringRef key, int64_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueUInt8(CFStringRef key, uint8_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int16_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt16Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueUInt8(CFStringRef key, uint8_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int16_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt16Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CFCMutableDictionary::AddValueUInt16(CFStringRef key, uint16_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int32_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueUInt16(CFStringRef key, uint16_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int32_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueUInt32(CFStringRef key, uint32_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int64_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueUInt32(CFStringRef key, uint32_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int64_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CFCMutableDictionary::AddValueUInt64(CFStringRef key, uint64_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // The number may appear negative if the MSBit is set in "value". Due to a limitation of
+ // CFNumber, there isn't a way to have it show up otherwise as of this writing.
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CFCMutableDictionary::SetValueUInt64(CFStringRef key, uint64_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // The number may appear negative if the MSBit is set in "value". Due to a limitation of
+ // CFNumber, there isn't a way to have it show up otherwise as of this writing.
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueCString(CFStringRef key, const char *cstr, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCString cf_str(cstr, kCFStringEncodingUTF8);
+ if (cf_str.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_str.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueCString(CFStringRef key, const char *cstr, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCString cf_str(cstr, kCFStringEncodingUTF8);
+ if (cf_str.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_str.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void
+CFCMutableDictionary::RemoveAllValues()
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ ::CFDictionaryRemoveAllValues(dict);
+}
+
+void
+CFCMutableDictionary::RemoveValue(const void *value)
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ ::CFDictionaryRemoveValue(dict, value);
+}
+void
+CFCMutableDictionary::ReplaceValue(const void *key, const void *value)
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ ::CFDictionaryReplaceValue (dict, key, value);
+}
+
diff --git a/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.h b/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.h
new file mode 100644
index 00000000000..de32ead3103
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.h
@@ -0,0 +1,77 @@
+//===-- CFCMutableDictionary.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFMutableDictionary_h_
+#define CoreFoundationCPP_CFMutableDictionary_h_
+
+#include "CFCReleaser.h"
+
+class CFCMutableDictionary : public CFCReleaser<CFMutableDictionaryRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCMutableDictionary(CFMutableDictionaryRef s = NULL);
+ CFCMutableDictionary(const CFCMutableDictionary& rhs);
+ virtual ~CFCMutableDictionary();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const CFCMutableDictionary&
+ operator=(const CFCMutableDictionary& rhs);
+
+
+ CFIndex GetCount() const;
+ CFIndex GetCountOfKey(const void *value) const;
+ CFIndex GetCountOfValue(const void *value) const;
+ void GetKeysAndValues(const void **keys, const void **values) const;
+ const void * GetValue(const void *key) const;
+ Boolean GetValueIfPresent(const void *key, const void **value_handle) const;
+ bool AddValue(CFStringRef key, const void *value, bool can_create = false);
+ bool SetValue(CFStringRef key, const void *value, bool can_create = false);
+ bool AddValueSInt8(CFStringRef key, int8_t value, bool can_create = false);
+ bool SetValueSInt8(CFStringRef key, int8_t value, bool can_create = false);
+ bool AddValueSInt16(CFStringRef key, int16_t value, bool can_create = false);
+ bool SetValueSInt16(CFStringRef key, int16_t value, bool can_create = false);
+ bool AddValueSInt32(CFStringRef key, int32_t value, bool can_create = false);
+ bool SetValueSInt32(CFStringRef key, int32_t value, bool can_create = false);
+ bool AddValueSInt64(CFStringRef key, int64_t value, bool can_create = false);
+ bool SetValueSInt64(CFStringRef key, int64_t value, bool can_create = false);
+ bool AddValueUInt8(CFStringRef key, uint8_t value, bool can_create = false);
+ bool SetValueUInt8(CFStringRef key, uint8_t value, bool can_create = false);
+ bool AddValueUInt16(CFStringRef key, uint16_t value, bool can_create = false);
+ bool SetValueUInt16(CFStringRef key, uint16_t value, bool can_create = false);
+ bool AddValueUInt32(CFStringRef key, uint32_t value, bool can_create = false);
+ bool SetValueUInt32(CFStringRef key, uint32_t value, bool can_create = false);
+ bool AddValueUInt64(CFStringRef key, uint64_t value, bool can_create = false);
+ bool SetValueUInt64(CFStringRef key, uint64_t value, bool can_create = false);
+ bool AddValueCString(CFStringRef key, const char *cstr, bool can_create = false);
+ bool SetValueCString(CFStringRef key, const char *cstr, bool can_create = false);
+ void RemoveValue(const void *value);
+ void ReplaceValue(const void *key, const void *value);
+ void RemoveAllValues();
+ CFMutableDictionaryRef Dictionary(bool can_create);
+
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from CFCMutableDictionary can see and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For CFCMutableDictionary only
+ //------------------------------------------------------------------
+
+};
+
+
+#endif // CoreFoundationCPP_CFMutableDictionary_h_
diff --git a/lldb/source/Host/macosx/cfcpp/CFCMutableSet.cpp b/lldb/source/Host/macosx/cfcpp/CFCMutableSet.cpp
new file mode 100644
index 00000000000..cd253704e2d
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCMutableSet.cpp
@@ -0,0 +1,114 @@
+//===-- CFCMutableSet.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCMutableSet.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+//----------------------------------------------------------------------
+// CFCString constructor
+//----------------------------------------------------------------------
+CFCMutableSet::CFCMutableSet(CFMutableSetRef s) :
+ CFCReleaser<CFMutableSetRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableSet copy constructor
+//----------------------------------------------------------------------
+CFCMutableSet::CFCMutableSet(const CFCMutableSet& rhs) :
+ CFCReleaser<CFMutableSetRef> (rhs)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableSet copy constructor
+//----------------------------------------------------------------------
+const CFCMutableSet&
+CFCMutableSet::operator=(const CFCMutableSet& rhs)
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCMutableSet::~CFCMutableSet()
+{
+}
+
+
+CFIndex
+CFCMutableSet::GetCount() const
+{
+ CFMutableSetRef set = get();
+ if (set)
+ return ::CFSetGetCount (set);
+ return 0;
+}
+
+CFIndex
+CFCMutableSet::GetCountOfValue(const void *value) const
+{
+ CFMutableSetRef set = get();
+ if (set)
+ return ::CFSetGetCountOfValue (set, value);
+ return 0;
+}
+
+const void *
+CFCMutableSet::GetValue(const void *value) const
+{
+ CFMutableSetRef set = get();
+ if (set)
+ return ::CFSetGetValue(set, value);
+ return NULL;
+}
+
+
+const void *
+CFCMutableSet::AddValue(const void *value, bool can_create)
+{
+ CFMutableSetRef set = get();
+ if (set == NULL)
+ {
+ if (can_create == false)
+ return false;
+ set = ::CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
+ reset ( set );
+ }
+ if (set != NULL)
+ {
+ ::CFSetAddValue(set, value);
+ return value;
+ }
+ return NULL;
+}
+
+void
+CFCMutableSet::RemoveValue(const void *value)
+{
+ CFMutableSetRef set = get();
+ if (set)
+ ::CFSetRemoveValue(set, value);
+}
+
+void
+CFCMutableSet::RemoveAllValues()
+{
+ CFMutableSetRef set = get();
+ if (set)
+ ::CFSetRemoveAllValues(set);
+}
+
diff --git a/lldb/source/Host/macosx/cfcpp/CFCMutableSet.h b/lldb/source/Host/macosx/cfcpp/CFCMutableSet.h
new file mode 100644
index 00000000000..78f7a8be81d
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCMutableSet.h
@@ -0,0 +1,53 @@
+//===-- CFCMutableSet.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFMutableSet_h_
+#define CoreFoundationCPP_CFMutableSet_h_
+
+#include "CFCReleaser.h"
+
+class CFCMutableSet : public CFCReleaser<CFMutableSetRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCMutableSet(CFMutableSetRef s = NULL);
+ CFCMutableSet(const CFCMutableSet& rhs);
+ virtual ~CFCMutableSet();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const CFCMutableSet&
+ operator=(const CFCMutableSet& rhs);
+
+
+ CFIndex GetCount() const;
+ CFIndex GetCountOfValue(const void *value) const;
+ const void * GetValue(const void *value) const;
+ const void * AddValue(const void *value, bool can_create);
+ void RemoveValue(const void *value);
+ void RemoveAllValues();
+
+
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from CFCMutableSet can see and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For CFCMutableSet only
+ //------------------------------------------------------------------
+
+};
+
+#endif // CoreFoundationCPP_CFMutableSet_h_
diff --git a/lldb/source/Host/macosx/cfcpp/CFCReleaser.h b/lldb/source/Host/macosx/cfcpp/CFCReleaser.h
new file mode 100644
index 00000000000..cd35de6d665
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCReleaser.h
@@ -0,0 +1,155 @@
+//===-- CFCReleaser.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFReleaser_h_
+#define CoreFoundationCPP_CFReleaser_h_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#ifdef __cplusplus
+
+#include <assert.h>
+
+//----------------------------------------------------------------------
+// Templatized CF helper class that can own any CF pointer and will
+// call CFRelease() on any valid pointer it owns unless that pointer is
+// explicitly released using the release() member function. This class
+// is designed to mimic the std::auto_ptr<T> class and has all of the
+// same functions. The one thing to watch out for is the
+// CFCReleaser<T>::release() function won't actually CFRelease any owned
+// pointer, it is designed to relinquish ownwership of the pointer just
+// like std:auto_ptr<T>::release() does.
+//----------------------------------------------------------------------
+template <class T>
+class CFCReleaser
+{
+public:
+ //----------------------------------------------------------
+ // Constructor that takes a pointer to a CF object that is
+ // to be released when this object goes out of scope
+ //----------------------------------------------------------
+ CFCReleaser(T ptr = NULL) :
+ _ptr(ptr)
+ {
+ }
+
+ //----------------------------------------------------------
+ // Copy constructor
+ //
+ // Note that copying a CFCReleaser will not transfer
+ // ownership of the contained pointer, but it will bump its
+ // reference count. This is where this class differs from
+ // std::auto_ptr.
+ //----------------------------------------------------------
+ CFCReleaser(const CFCReleaser& rhs) :
+ _ptr(rhs.get())
+ {
+ if (get())
+ ::CFRetain(get());
+ }
+
+
+ //----------------------------------------------------------
+ // The destructor will release the pointer that it contains
+ // if it has a valid pointer.
+ //----------------------------------------------------------
+ virtual ~CFCReleaser()
+ {
+ reset();
+ }
+
+ //----------------------------------------------------------
+ // Assignment operator.
+ //
+ // Note that assigning one CFCReleaser to another will
+ // not transfer ownership of the contained pointer, but it
+ // will bump its reference count. This is where this class
+ // differs from std::auto_ptr.
+ //----------------------------------------------------------
+ CFCReleaser&
+ operator= (const CFCReleaser<T>& rhs)
+ {
+ if (this != &rhs)
+ {
+ // Replace our owned pointer with the new one
+ reset(rhs.get());
+ // Retain the current pointer that we own
+ if (get())
+ ::CFRetain(get());
+ }
+ return *this;
+ }
+
+ //----------------------------------------------------------
+ // Get the address of the contained type in case it needs
+ // to be passed to a function that will fill in a pointer
+ // value. The function currently will assert if _ptr is not
+ // NULL because the only time this method should be used is
+ // if another function will modify the contents, and we
+ // could leak a pointer if this is not NULL. If the
+ // assertion fires, check the offending code, or call
+ // reset() prior to using the "ptr_address()" member to make
+ // sure any owned objects has CFRelease called on it.
+ //----------------------------------------------------------
+ T*
+ ptr_address()
+ {
+ assert (_ptr == NULL);
+ return &_ptr;
+ }
+
+ //----------------------------------------------------------
+ // Access the pointer itself
+ //----------------------------------------------------------
+ T
+ get()
+ {
+ return _ptr;
+ }
+
+ const T
+ get() const
+ {
+ return _ptr;
+ }
+
+
+ //----------------------------------------------------------
+ // Set a new value for the pointer and CFRelease our old
+ // value if we had a valid one.
+ //----------------------------------------------------------
+ void
+ reset(T ptr = NULL)
+ {
+ if ((_ptr != NULL) && (ptr != _ptr))
+ ::CFRelease(_ptr);
+ _ptr = ptr;
+ }
+
+ //----------------------------------------------------------
+ // Release ownership without calling CFRelease. This class
+ // is designed to mimic std::auto_ptr<T>, so the release
+ // method releases ownership of the contained pointer
+ // and does NOT call CFRelease.
+ //----------------------------------------------------------
+ T
+ release()
+ {
+ T tmp = _ptr;
+ _ptr = NULL;
+ return tmp;
+ }
+
+private:
+ T _ptr;
+};
+
+#endif // #ifdef __cplusplus
+#endif // #ifndef CoreFoundationCPP_CFReleaser_h_
+
diff --git a/lldb/source/Host/macosx/cfcpp/CFCString.cpp b/lldb/source/Host/macosx/cfcpp/CFCString.cpp
new file mode 100644
index 00000000000..81a96b82499
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCString.cpp
@@ -0,0 +1,195 @@
+//===-- CFCString.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCString.h"
+#include <string>
+#include <glob.h>
+
+//----------------------------------------------------------------------
+// CFCString constructor
+//----------------------------------------------------------------------
+CFCString::CFCString(CFStringRef s) :
+ CFCReleaser<CFStringRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCString copy constructor
+//----------------------------------------------------------------------
+CFCString::CFCString(const CFCString& rhs) :
+ CFCReleaser<CFStringRef> (rhs)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFCString copy constructor
+//----------------------------------------------------------------------
+CFCString&
+CFCString::operator=(const CFCString& rhs)
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+CFCString::CFCString (const char *cstr, CFStringEncoding cstr_encoding) :
+ CFCReleaser<CFStringRef> ()
+{
+ if (cstr && cstr[0])
+ {
+ reset(::CFStringCreateWithCString(kCFAllocatorDefault, cstr, cstr_encoding));
+ }
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCString::~CFCString()
+{
+}
+
+const char *
+CFCString::GetFileSystemRepresentation(std::string& s)
+{
+ return CFCString::FileSystemRepresentation(get(), s);
+}
+
+CFStringRef
+CFCString::SetFileSystemRepresentation (const char *path)
+{
+ CFStringRef new_value = NULL;
+ if (path && path[0])
+ new_value = ::CFStringCreateWithFileSystemRepresentation (kCFAllocatorDefault, path);
+ reset(new_value);
+ return get();
+}
+
+
+CFStringRef
+CFCString::SetFileSystemRepresentationFromCFType (CFTypeRef cf_type)
+{
+ CFStringRef new_value = NULL;
+ if (cf_type != NULL)
+ {
+ CFTypeID cf_type_id = ::CFGetTypeID(cf_type);
+
+ if (cf_type_id == ::CFStringGetTypeID())
+ {
+ // Retain since we are using the existing object
+ new_value = (CFStringRef)::CFRetain(cf_type);
+ }
+ else if (cf_type_id == ::CFURLGetTypeID())
+ {
+ new_value = ::CFURLCopyFileSystemPath((CFURLRef)cf_type, kCFURLPOSIXPathStyle);
+ }
+ }
+ reset(new_value);
+ return get();
+}
+
+CFStringRef
+CFCString::SetFileSystemRepresentationAndExpandTilde (const char *path)
+{
+ std::string expanded_path;
+ if (CFCString::ExpandTildeInPath(path, expanded_path))
+ SetFileSystemRepresentation(expanded_path.c_str());
+ else
+ reset();
+ return get();
+}
+
+const char *
+CFCString::UTF8(std::string& str)
+{
+ return CFCString::UTF8(get(), str);
+}
+
+// Static function that puts a copy of the UTF8 contents of CF_STR into STR
+// and returns the C string pointer that is contained in STR when successful, else
+// NULL is returned. This allows the std::string parameter to own the extracted string,
+// and also allows that string to be returned as a C string pointer that can be used.
+
+const char *
+CFCString::UTF8 (CFStringRef cf_str, std::string& str)
+{
+ if (cf_str)
+ {
+ const CFStringEncoding encoding = kCFStringEncodingUTF8;
+ CFIndex max_utf8_str_len = CFStringGetLength (cf_str);
+ max_utf8_str_len = CFStringGetMaximumSizeForEncoding (max_utf8_str_len, encoding);
+ if (max_utf8_str_len > 0)
+ {
+ str.resize(max_utf8_str_len);
+ if (!str.empty())
+ {
+ if (CFStringGetCString (cf_str, &str[0], str.size(), encoding))
+ {
+ str.resize(strlen(str.c_str()));
+ return str.c_str();
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+const char*
+CFCString::ExpandTildeInPath(const char* path, std::string &expanded_path)
+{
+ glob_t globbuf;
+ if (::glob (path, GLOB_TILDE, NULL, &globbuf) == 0)
+ {
+ expanded_path = globbuf.gl_pathv[0];
+ ::globfree (&globbuf);
+ }
+ else
+ expanded_path.clear();
+
+ return expanded_path.c_str();
+}
+
+// Static function that puts a copy of the file system representation of CF_STR
+// into STR and returns the C string pointer that is contained in STR when
+// successful, else NULL is returned. This allows the std::string parameter
+// to own the extracted string, and also allows that string to be returned as
+// a C string pointer that can be used.
+
+const char *
+CFCString::FileSystemRepresentation (CFStringRef cf_str, std::string& str)
+{
+ if (cf_str)
+ {
+ CFIndex max_length = ::CFStringGetMaximumSizeOfFileSystemRepresentation (cf_str);
+ if (max_length > 0)
+ {
+ str.resize(max_length);
+ if (!str.empty())
+ {
+ if (::CFStringGetFileSystemRepresentation (cf_str, &str[0], str.size()))
+ {
+ str.erase(::strlen(str.c_str()));
+ return str.c_str();
+ }
+ }
+ }
+ }
+ str.erase();
+ return NULL;
+}
+
+
+CFIndex
+CFCString::GetLength() const
+{
+ CFStringRef str = get();
+ if (str)
+ return CFStringGetLength (str);
+ return 0;
+}
diff --git a/lldb/source/Host/macosx/cfcpp/CFCString.h b/lldb/source/Host/macosx/cfcpp/CFCString.h
new file mode 100644
index 00000000000..521d2c0a51b
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CFCString.h
@@ -0,0 +1,41 @@
+//===-- CFCString.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFString_h_
+#define CoreFoundationCPP_CFString_h_
+
+#include <iosfwd>
+
+#include "CFCReleaser.h"
+
+class CFCString : public CFCReleaser<CFStringRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCString (CFStringRef cf_str = NULL);
+ CFCString (const char *s, CFStringEncoding encoding);
+ CFCString (const CFCString& rhs);
+ CFCString& operator= (const CFCString& rhs);
+ virtual ~CFCString ();
+
+ const char * GetFileSystemRepresentation (std::string& str);
+ CFStringRef SetFileSystemRepresentation (const char *path);
+ CFStringRef SetFileSystemRepresentationFromCFType (CFTypeRef cf_type);
+ CFStringRef SetFileSystemRepresentationAndExpandTilde (const char *path);
+ const char * UTF8 (std::string& str);
+ CFIndex GetLength() const;
+ static const char *UTF8 (CFStringRef cf_str, std::string& str);
+ static const char *FileSystemRepresentation (CFStringRef cf_str, std::string& str);
+ static const char *ExpandTildeInPath(const char* path, std::string &expanded_path);
+
+};
+
+#endif // #ifndef CoreFoundationCPP_CFString_h_
diff --git a/lldb/source/Host/macosx/cfcpp/CoreFoundationCPP.h b/lldb/source/Host/macosx/cfcpp/CoreFoundationCPP.h
new file mode 100644
index 00000000000..6843e2649cd
--- /dev/null
+++ b/lldb/source/Host/macosx/cfcpp/CoreFoundationCPP.h
@@ -0,0 +1,30 @@
+//===-- CoreFoundationCPP.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// CoreFoundationCPP.h
+// CoreFoundationCPP
+//
+// Created by Greg Clayton on 4/23/09.
+//
+//
+//----------------------------------------------------------------------
+
+#ifndef CoreFoundationCPP_CoreFoundationCPP_H_
+#define CoreFoundationCPP_CoreFoundationCPP_H_
+
+#include <CoreFoundationCPP/CFCBundle.h>
+#include <CoreFoundationCPP/CFCData.h>
+#include <CoreFoundationCPP/CFCReleaser.h>
+#include <CoreFoundationCPP/CFCMutableArray.h>
+#include <CoreFoundationCPP/CFCMutableDictionary.h>
+#include <CoreFoundationCPP/CFCMutableSet.h>
+#include <CoreFoundationCPP/CFCString.h>
+
+#endif // CoreFoundationCPP_CoreFoundationCPP_H_
diff --git a/lldb/source/Interpreter/CommandCompletions.cpp b/lldb/source/Interpreter/CommandCompletions.cpp
new file mode 100644
index 00000000000..a299ffb098f
--- /dev/null
+++ b/lldb/source/Interpreter/CommandCompletions.cpp
@@ -0,0 +1,414 @@
+//===-- CommandCompletions.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/Args.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+
+
+using namespace lldb_private;
+
+CommandCompletions::CommonCompletionElement
+CommandCompletions::g_common_completions[] =
+{
+ {eCustomCompletion, NULL},
+ {eSourceFileCompletion, CommandCompletions::SourceFiles},
+ {eDiskFileCompletion, NULL},
+ {eSymbolCompletion, CommandCompletions::Symbols},
+ {eModuleCompletion, CommandCompletions::Modules},
+ {eNoCompletion, NULL} // This one has to be last in the list.
+};
+
+bool
+CommandCompletions::InvokeCommonCompletionCallbacks (uint32_t completion_mask,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ lldb_private::CommandInterpreter *interpreter,
+ SearchFilter *searcher,
+ lldb_private::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 (completion_str,
+ match_start_point,
+ max_return_elements,
+ interpreter,
+ searcher,
+ matches);
+ }
+ }
+ return handled;
+}
+
+int
+CommandCompletions::SourceFiles (const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ lldb_private::CommandInterpreter *interpreter,
+ SearchFilter *searcher,
+ lldb_private::StringList &matches)
+{
+ // Find some way to switch "include support files..."
+ SourceFileCompleter completer (false, partial_file_name, match_start_point, max_return_elements, interpreter,
+ matches);
+
+ if (searcher == NULL)
+ {
+ lldb::TargetSP target_sp = interpreter->Context()->GetTarget()->GetSP();
+ SearchFilter null_searcher (target_sp);
+ completer.DoCompletion (&null_searcher);
+ }
+ else
+ {
+ completer.DoCompletion (searcher);
+ }
+ return matches.GetSize();
+}
+
+int
+CommandCompletions::Modules (const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ lldb_private::CommandInterpreter *interpreter,
+ SearchFilter *searcher,
+ lldb_private::StringList &matches)
+{
+ ModuleCompleter completer(partial_file_name, match_start_point, max_return_elements, interpreter, matches);
+
+ if (searcher == NULL)
+ {
+ lldb::TargetSP target_sp = interpreter->Context()->GetTarget()->GetSP();
+ SearchFilter null_searcher (target_sp);
+ completer.DoCompletion (&null_searcher);
+ }
+ else
+ {
+ completer.DoCompletion (searcher);
+ }
+ return matches.GetSize();
+}
+
+int
+CommandCompletions::Symbols (const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ lldb_private::CommandInterpreter *interpreter,
+ SearchFilter *searcher,
+ lldb_private::StringList &matches)
+{
+ SymbolCompleter completer(partial_file_name, match_start_point, max_return_elements, interpreter, matches);
+
+ if (searcher == NULL)
+ {
+ lldb::TargetSP target_sp = interpreter->Context()->GetTarget()->GetSP();
+ SearchFilter null_searcher (target_sp);
+ completer.DoCompletion (&null_searcher);
+ }
+ else
+ {
+ completer.DoCompletion (searcher);
+ }
+ return matches.GetSize();
+}
+
+CommandCompletions::Completer::Completer (
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ StringList &matches
+) :
+ m_completion_str (completion_str),
+ m_match_start_point (match_start_point),
+ m_max_return_elements (max_return_elements),
+ m_interpreter (interpreter),
+ m_matches (matches)
+{
+}
+
+CommandCompletions::Completer::~Completer ()
+{
+
+}
+
+//----------------------------------------------------------------------
+// SourceFileCompleter
+//----------------------------------------------------------------------
+
+CommandCompletions::SourceFileCompleter::SourceFileCompleter (
+ bool include_support_files,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ StringList &matches
+) :
+ CommandCompletions::Completer (completion_str, match_start_point, max_return_elements, interpreter, matches),
+ m_include_support_files (include_support_files),
+ m_matching_files()
+{
+ FileSpec partial_spec (m_completion_str.c_str());
+ 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 == ')')
+ return true;
+ else
+ return false;
+}
+CommandCompletions::SymbolCompleter::SymbolCompleter (
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ StringList &matches
+) :
+ CommandCompletions::Completer (completion_str, match_start_point, max_return_elements, interpreter, matches)
+{
+ std::string regex_str ("^");
+ regex_str.append(completion_str);
+ regex_str.append(".*");
+ std::string::iterator pos;
+
+ pos = find_if(regex_str.begin(), regex_str.end(), regex_chars);
+ while (pos < regex_str.end()) {
+ pos = regex_str.insert(pos, '\\');
+ pos += 2;
+ pos = find_if(pos, 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
+)
+{
+ SymbolContextList func_list;
+ SymbolContextList sym_list;
+
+ if (context.module_sp != NULL)
+ {
+ if (context.module_sp)
+ {
+ context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, lldb::eSymbolTypeCode, sym_list);
+ context.module_sp->FindFunctions (m_regex, true, func_list);
+ }
+
+ SymbolContext sc;
+ // Now add the functions & symbols to the list - only add if unique:
+ for (int i = 0; i < func_list.GetSize(); i++)
+ {
+ if (func_list.GetContextAtIndex(i, sc))
+ {
+ if (sc.function)
+ {
+ m_match_set.insert (sc.function->GetMangled().GetDemangledName());
+ }
+ }
+ }
+
+ for (int i = 0; i < sym_list.GetSize(); i++)
+ {
+ if (sym_list.GetContextAtIndex(i, sc))
+ {
+ if (sc.symbol && sc.symbol->GetAddressRangePtr())
+ {
+ m_match_set.insert (sc.symbol->GetMangled().GetDemangledName());
+ }
+ }
+ }
+ }
+ 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 (
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ StringList &matches
+) :
+ CommandCompletions::Completer (completion_str, match_start_point, max_return_elements, interpreter, matches)
+{
+ FileSpec partial_spec (m_completion_str.c_str());
+ 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 != NULL)
+ {
+ 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/lldb/source/Interpreter/CommandContext.cpp b/lldb/source/Interpreter/CommandContext.cpp
new file mode 100644
index 00000000000..012611c5262
--- /dev/null
+++ b/lldb/source/Interpreter/CommandContext.cpp
@@ -0,0 +1,77 @@
+//===-- CommandContext.cpp --------------------------------------*- 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/CommandContext.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandContext::CommandContext () :
+ m_exe_ctx ()
+{
+}
+
+CommandContext::~CommandContext ()
+{
+}
+
+Target *
+CommandContext::GetTarget()
+{
+ return Debugger::GetSharedInstance().GetCurrentTarget().get();
+}
+
+
+ExecutionContext &
+CommandContext::GetExecutionContext()
+{
+ return m_exe_ctx;
+}
+
+void
+CommandContext::Update (ExecutionContext *override_context)
+{
+ m_exe_ctx.Clear();
+
+ if (override_context != NULL)
+ {
+ m_exe_ctx.target = override_context->target;
+ m_exe_ctx.process = override_context->process;
+ m_exe_ctx.thread = override_context->thread;
+ m_exe_ctx.frame = override_context->frame;
+ }
+ else
+ {
+ TargetSP target_sp (Debugger::GetSharedInstance().GetCurrentTarget());
+ if (target_sp)
+ {
+ m_exe_ctx.process = target_sp->GetProcessSP().get();
+ if (m_exe_ctx.process && m_exe_ctx.process->IsRunning() == false)
+ {
+ m_exe_ctx.thread = m_exe_ctx.process->GetThreadList().GetCurrentThread().get();
+ if (m_exe_ctx.thread == NULL)
+ m_exe_ctx.thread = m_exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get();
+ if (m_exe_ctx.thread)
+ {
+ m_exe_ctx.frame = m_exe_ctx.thread->GetCurrentFrame().get();
+ if (m_exe_ctx.frame == NULL)
+ m_exe_ctx.frame = m_exe_ctx.thread->GetStackFrameAtIndex (0).get();
+ }
+ }
+ }
+ }
+}
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
new file mode 100644
index 00000000000..ed85b33bab3
--- /dev/null
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -0,0 +1,1300 @@
+//===-- 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 <string>
+
+#include <getopt.h>
+#include <stdlib.h>
+
+#include "CommandObjectAdd.h"
+#include "CommandObjectAlias.h"
+#include "CommandObjectAppend.h"
+#include "CommandObjectApropos.h"
+#include "CommandObjectArgs.h"
+#include "CommandObjectBreakpoint.h"
+#include "CommandObjectCall.h"
+#include "CommandObjectDelete.h"
+#include "CommandObjectDisassemble.h"
+#include "CommandObjectExpression.h"
+#include "CommandObjectFile.h"
+#include "CommandObjectFrame.h"
+#include "CommandObjectHelp.h"
+#include "CommandObjectImage.h"
+#include "CommandObjectInfo.h"
+#include "CommandObjectLog.h"
+#include "CommandObjectMemory.h"
+#include "CommandObjectProcess.h"
+#include "CommandObjectQuit.h"
+#include "CommandObjectRegexCommand.h"
+#include "CommandObjectRegister.h"
+#include "CommandObjectRemove.h"
+#include "CommandObjectScript.h"
+#include "CommandObjectSelect.h"
+#include "CommandObjectSet.h"
+#include "CommandObjectSettings.h"
+#include "CommandObjectShow.h"
+#include "CommandObjectSource.h"
+#include "CommandObjectSourceFile.h"
+#include "CommandObjectStatus.h"
+#include "CommandObjectSyntax.h"
+#include "CommandObjectTarget.h"
+#include "CommandObjectThread.h"
+#include "CommandObjectTranslate.h"
+#include "CommandObjectUnalias.h"
+#include "CommandObjectVariable.h"
+
+#include "lldb/Core/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/TargetList.h"
+
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandInterpreter::CommandInterpreter
+(
+ ScriptLanguage script_language,
+ bool synchronous_execution,
+ Listener *listener,
+ SourceManager& source_manager
+) :
+ Broadcaster ("CommandInterpreter"),
+ m_script_language (script_language),
+ m_synchronous_execution (synchronous_execution),
+ m_listener (listener),
+ m_source_manager (source_manager)
+{
+}
+
+void
+CommandInterpreter::Initialize ()
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ CommandReturnObject result;
+
+ LoadCommandDictionary ();
+
+ InitializeVariables ();
+
+ // Set up some initial aliases.
+ result.Clear(); HandleCommand ("alias q quit", false, result);
+ result.Clear(); HandleCommand ("alias run process launch", false, result);
+ result.Clear(); HandleCommand ("alias r process launch", false, result);
+ result.Clear(); HandleCommand ("alias c process continue", false, result);
+ result.Clear(); HandleCommand ("alias continue process continue", false, result);
+ result.Clear(); HandleCommand ("alias expr expression", false, result);
+ result.Clear(); HandleCommand ("alias exit quit", false, result);
+ result.Clear(); HandleCommand ("alias bt thread backtrace", false, result);
+ result.Clear(); HandleCommand ("alias si thread step-inst", false, result);
+ result.Clear(); HandleCommand ("alias step thread step-in", false, result);
+ result.Clear(); HandleCommand ("alias s thread step-in", false, result);
+ result.Clear(); HandleCommand ("alias next thread step-over", false, result);
+ result.Clear(); HandleCommand ("alias n thread step-over", false, result);
+ result.Clear(); HandleCommand ("alias finish thread step-out", false, result);
+ result.Clear(); HandleCommand ("alias x memory read", false, result);
+ result.Clear(); HandleCommand ("alias l source-file", false, result);
+ result.Clear(); HandleCommand ("alias list source-file", false, result);
+}
+
+void
+CommandInterpreter::InitializeVariables ()
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ m_variables["prompt"] =
+ StateVariableSP (new StateVariable ("prompt",
+ "(lldb) ",
+ false,
+ "The debugger prompt displayed for the user.",
+ StateVariable::BroadcastPromptChange));
+
+ m_variables["run-args"] =
+ StateVariableSP (new StateVariable ("run-args",
+ (Args*)NULL,
+ "An argument list containing the arguments to be passed to the executable when it is launched."));
+
+
+ m_variables["env-vars"] =
+ StateVariableSP (new StateVariable ("env-vars",
+ (Args*)NULL,
+ "A list of strings containing the environment variables to be passed to the executable's environment."));
+
+ m_variables["input-path"] =
+ StateVariableSP (new StateVariable ("input-path",
+ "/dev/stdin",
+ false,
+ "The file/path to be used by the executable program for reading its input."));
+
+ m_variables["output-path"] =
+ StateVariableSP (new StateVariable ( "output-path",
+ "/dev/stdout",
+ false,
+ "The file/path to be used by the executable program for writing its output."));
+
+ m_variables["error-path"] =
+ StateVariableSP (new StateVariable ("error-path",
+ "/dev/stderr",
+ false,
+ "The file/path to be used by the executable program for writing its error messages."));
+
+ m_variables["arch"] =
+ StateVariableSP (new StateVariable ("arch",
+ "",
+ false,
+ "The architecture to be used for running the executable (e.g. i386, x86_64, etc)."));
+
+ m_variables["script-lang"] =
+ StateVariableSP (new StateVariable ("script-lang",
+ "Python",
+ false,
+ "The script language to be used for evaluating user-written scripts.",
+ StateVariable::VerifyScriptLanguage));
+
+ m_variables["term-width"] =
+ StateVariableSP (new StateVariable ("term-width",
+ 80,
+ "The maximum number of columns to use for displaying text."));
+
+}
+
+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__);
+
+ // **** IMPORTANT **** IMPORTANT *** IMPORTANT *** **** IMPORTANT **** IMPORTANT *** IMPORTANT ***
+ //
+ // Command objects that are used as cross reference objects (i.e. they inherit from CommandObjectCrossref)
+ // *MUST* be created and put into the command dictionary *BEFORE* any multi-word commands (which may use
+ // the cross-referencing stuff) are created!!!
+ //
+ // **** IMPORTANT **** IMPORTANT *** IMPORTANT *** **** IMPORTANT **** IMPORTANT *** IMPORTANT ***
+
+
+ // Command objects that inherit from CommandObjectCrossref must be created before other command objects
+ // are created. This is so that when another command is created that needs to go into a crossref object,
+ // the crossref object exists and is ready to take the cross reference. Put the cross referencing command
+ // objects into the CommandDictionary now, so they are ready for use when the other commands get created.
+
+ m_command_dict["select"] = CommandObjectSP (new CommandObjectSelect ());
+ m_command_dict["info"] = CommandObjectSP (new CommandObjectInfo ());
+ m_command_dict["delete"] = CommandObjectSP (new CommandObjectDelete ());
+
+ // Non-CommandObjectCrossref commands can now be created.
+
+ //m_command_dict["add"] = CommandObjectSP (new CommandObjectAdd ());
+ m_command_dict["alias"] = CommandObjectSP (new CommandObjectAlias ());
+ m_command_dict["append"] = CommandObjectSP (new CommandObjectAppend ());
+ m_command_dict["apropos"] = CommandObjectSP (new CommandObjectApropos ());
+ //m_command_dict["args"] = CommandObjectSP (new CommandObjectArgs ());
+ m_command_dict["breakpoint"]= CommandObjectSP (new CommandObjectMultiwordBreakpoint (this));
+ m_command_dict["call"] = CommandObjectSP (new CommandObjectCall ());
+ m_command_dict["disassemble"] = CommandObjectSP (new CommandObjectDisassemble ());
+ m_command_dict["expression"]= CommandObjectSP (new CommandObjectExpression ());
+ m_command_dict["file"] = CommandObjectSP (new CommandObjectFile ());
+ m_command_dict["frame"] = CommandObjectSP (new CommandObjectMultiwordFrame (this));
+ m_command_dict["help"] = CommandObjectSP (new CommandObjectHelp ());
+ m_command_dict["image"] = CommandObjectSP (new CommandObjectImage (this));
+ m_command_dict["log"] = CommandObjectSP (new CommandObjectLog (this));
+ m_command_dict["memory"] = CommandObjectSP (new CommandObjectMemory (this));
+ m_command_dict["process"] = CommandObjectSP (new CommandObjectMultiwordProcess (this));
+ m_command_dict["quit"] = CommandObjectSP (new CommandObjectQuit ());
+ m_command_dict["register"] = CommandObjectSP (new CommandObjectRegister (this));
+ //m_command_dict["remove"] = CommandObjectSP (new CommandObjectRemove ());
+ m_command_dict["script"] = CommandObjectSP (new CommandObjectScript (m_script_language));
+ m_command_dict["set"] = CommandObjectSP (new CommandObjectSet ());
+ m_command_dict["settings"] = CommandObjectSP (new CommandObjectSettings ());
+ m_command_dict["show"] = CommandObjectSP (new CommandObjectShow ());
+ m_command_dict["source"] = CommandObjectSP (new CommandObjectSource ());
+ m_command_dict["source-file"] = CommandObjectSP (new CommandObjectSourceFile ());
+ //m_command_dict["syntax"] = CommandObjectSP (new CommandObjectSyntax ());
+ m_command_dict["status"] = CommandObjectSP (new CommandObjectStatus ());
+ m_command_dict["target"] = CommandObjectSP (new CommandObjectMultiwordTarget (this));
+ m_command_dict["thread"] = CommandObjectSP (new CommandObjectMultiwordThread (this));
+ //m_command_dict["translate"] = CommandObjectSP (new CommandObjectTranslate ());
+ m_command_dict["unalias"] = CommandObjectSP (new CommandObjectUnalias ());
+ m_command_dict["variable"] = CommandObjectSP (new CommandObjectVariable (this));
+
+ std::auto_ptr<CommandObjectRegexCommand>
+ break_regex_cmd_ap(new CommandObjectRegexCommand ("regexp-break",
+ "Smart breakpoint command (using regular expressions).",
+ "regexp-break [<file>:<line>]\nregexp-break [<address>]\nregexp-break <...>", 2));
+ if (break_regex_cmd_ap.get())
+ {
+ if (break_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", "breakpoint set --file '%1' --line %2") &&
+ break_regex_cmd_ap->AddRegexCommand("^(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1") &&
+ break_regex_cmd_ap->AddRegexCommand("^[\"']?([-+]\\[.*\\])[\"']?[[:space:]]*$", "breakpoint set --name '%1'") &&
+ break_regex_cmd_ap->AddRegexCommand("^$", "breakpoint list") &&
+ break_regex_cmd_ap->AddRegexCommand("^(-.*)$", "breakpoint set %1") &&
+ break_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%1'"))
+ {
+ CommandObjectSP break_regex_cmd_sp(break_regex_cmd_ap.release());
+ m_command_dict[break_regex_cmd_sp->GetCommandName ()] = break_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 ret_val;
+
+ std::string cmd(cmd_cstr);
+
+ if (HasCommands())
+ {
+ pos = m_command_dict.find(cmd);
+ if (pos != m_command_dict.end())
+ ret_val = pos->second;
+ }
+
+ if (include_aliases && HasAliases())
+ {
+ pos = m_alias_dict.find(cmd);
+ if (pos != m_alias_dict.end())
+ ret_val = pos->second;
+ }
+
+ if (HasUserCommands())
+ {
+ pos = m_user_dict.find(cmd);
+ if (pos != m_user_dict.end())
+ ret_val = pos->second;
+ }
+
+ if (!exact && ret_val == NULL)
+ {
+ StringList local_matches;
+ if (matches == NULL)
+ matches = &local_matches;
+
+ int num_cmd_matches = 0;
+ int num_alias_matches = 0;
+ int num_user_matches = 0;
+ 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())
+ ret_val = pos->second;
+ }
+
+ if (num_cmd_matches != 1 && 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())
+ {
+ matches->Clear();
+ matches->AppendString (cmd.c_str());
+
+ ret_val = pos->second;
+ }
+ }
+
+ if (num_cmd_matches != 1 && num_alias_matches != 1 && 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())
+ {
+ matches->Clear();
+ matches->AppendString (cmd.c_str());
+
+ ret_val = pos->second;
+ }
+ }
+ }
+ else {
+ if (matches)
+ matches->AppendString (cmd_cstr);
+ }
+
+
+ return ret_val;
+}
+
+CommandObject *
+CommandInterpreter::GetCommandObject (const char *cmd_cstr, bool include_aliases, bool exact, StringList *matches)
+{
+ return GetCommandSP (cmd_cstr, include_aliases, exact, matches).get();
+}
+
+bool
+CommandInterpreter::CommandExists (const char *cmd)
+{
+ return m_command_dict.find(cmd) != m_command_dict.end();
+}
+
+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)
+{
+ 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;
+}
+
+StateVariable *
+CommandInterpreter::GetStateVariable(const char *name)
+{
+ VariableMap::const_iterator pos = m_variables.find(name);
+ if (pos != m_variables.end())
+ return pos->second.get();
+ return NULL;
+}
+
+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 != NULL)
+ {
+ OptionArgVector *options = option_arg_vector_sp.get();
+ for (int i = 0; i < options->size(); ++i)
+ {
+ OptionArgPair cur_option = (*options)[i];
+ std::string opt = cur_option.first;
+ std::string value = cur_option.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 ("'");
+}
+
+std::string
+CommandInterpreter::FindLongestCommandWord (CommandObject::CommandMap &dict)
+{
+ CommandObject::CommandMap::const_iterator pos;
+ int max_len = 0;
+ CommandObjectSP cmd_sp;
+ std::string longest_word;
+
+ for (pos = dict.begin(); pos != dict.end(); ++pos)
+ {
+ if ((max_len == 0)
+ || (strlen (pos->first.c_str()) > max_len))
+ {
+ longest_word = pos->first;
+ max_len = strlen (longest_word.c_str());
+ }
+ }
+
+ return longest_word;
+}
+
+void
+CommandInterpreter::GetHelp (CommandReturnObject &result)
+{
+ CommandObject::CommandMap::const_iterator pos;
+ result.AppendMessage("The following is a list of built-in, permanent debugger commands:");
+ result.AppendMessage("");
+ std::string longest_word = FindLongestCommandWord (m_command_dict);
+ uint32_t max_len = strlen (longest_word.c_str());
+
+ 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.size() > 0)
+ {
+ result.AppendMessage("The following is a list of your current command abbreviations (see 'alias' for more info):");
+ result.AppendMessage("");
+ longest_word = FindLongestCommandWord (m_alias_dict);
+ max_len = strlen (longest_word.c_str());
+ 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.size() > 0)
+ {
+ result.AppendMessage ("The following is a list of your current user-defined commands:");
+ result.AppendMessage("");
+ for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos)
+ {
+ result.AppendMessageWithFormat ("%s -- %s\n", pos->first.c_str(), pos->second->GetHelp());
+ }
+ result.AppendMessage("");
+ }
+
+ result.AppendMessage("For more information on any particular command, try 'help <command-name>'.");
+}
+
+void
+CommandInterpreter::ShowVariableValues (CommandReturnObject &result)
+{
+ result.AppendMessage ("Below is a list of all the debugger setting variables and their values:");
+
+ for (VariableMap::const_iterator pos = m_variables.begin(); pos != m_variables.end(); ++pos)
+ {
+ StateVariable *var = pos->second.get();
+ var->AppendVariableInformation (result);
+ }
+}
+
+void
+CommandInterpreter::ShowVariableHelp (CommandReturnObject &result)
+{
+ result.AppendMessage ("Below is a list of all the internal debugger variables that are settable:");
+ for (VariableMap::const_iterator pos = m_variables.begin(); pos != m_variables.end(); ++pos)
+ {
+ StateVariable *var = pos->second.get();
+ result.AppendMessageWithFormat (" %s -- %s \n", var->GetName(), var->GetHelp());
+ }
+}
+
+// Main entry point into the command_interpreter; this function takes a text
+// line containing a debugger command, with all its flags, options, etc,
+// parses the line and takes the appropriate actions.
+
+bool
+CommandInterpreter::HandleCommand (const char *command_line, bool add_to_history, CommandReturnObject &result,
+ ExecutionContext *override_context)
+{
+ // FIXME: there should probably be a mutex to make sure only one thread can
+ // run the interpreter at a time.
+
+ // TODO: this should be a logging channel in lldb.
+// if (DebugSelf())
+// {
+// result.AppendMessageWithFormat ("Processing command: %s\n", command_line);
+// }
+
+ m_current_context.Update (override_context);
+
+ if (command_line == NULL || command_line[0] == '\0')
+ {
+ if (m_command_history.empty())
+ {
+ result.AppendError ("empty command");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ command_line = m_command_history.back().c_str();
+ }
+ add_to_history = false;
+ }
+
+ Args command_args(command_line);
+
+ if (command_args.GetArgumentCount() > 0)
+ {
+ const char *command_cstr = command_args.GetArgumentAtIndex(0);
+ if (command_cstr)
+ {
+
+ // We're looking up the command object here. So first find an exact match to the
+ // command in the commands.
+
+ CommandObject *command_obj = GetCommandObject (command_cstr, false, true);
+
+ // If we didn't find an exact match to the command string in the commands, look in
+ // the aliases.
+
+ if (command_obj == NULL)
+ {
+ command_obj = GetCommandObject (command_cstr, true, true);
+ if (command_obj != NULL)
+ {
+ BuildAliasCommandArgs (command_obj, command_cstr, command_args, result);
+ if (!result.Succeeded())
+ return false;
+ }
+ }
+
+ // Finally, if there wasn't an exact match among the aliases, look for an inexact match.
+
+ if (command_obj == NULL)
+ command_obj = GetCommandObject(command_cstr, false, false);
+
+ if (command_obj)
+ {
+ if (command_obj->WantsRawCommandString())
+ {
+ const char *stripped_command = ::strstr (command_line, command_cstr);
+ if (stripped_command)
+ {
+ stripped_command += strlen(command_cstr);
+ while (isspace(*stripped_command))
+ ++stripped_command;
+ command_obj->ExecuteRawCommandString(stripped_command, Context(), this, result);
+ }
+ }
+ else
+ {
+ if (add_to_history)
+ m_command_history.push_back (command_line);
+
+ // Remove the command from the args.
+ command_args.Shift();
+ command_obj->ExecuteWithOptions (command_args, Context(), this, result);
+ }
+ }
+ else
+ {
+ StringList matches;
+ int num_matches;
+ int cursor_index = command_args.GetArgumentCount() - 1;
+ int cursor_char_position = strlen (command_args.GetArgumentAtIndex(command_args.GetArgumentCount() - 1));
+ num_matches = HandleCompletionMatches (command_args, cursor_index,
+ cursor_char_position,
+ 0, -1, matches);
+
+ if (num_matches > 0)
+ {
+ std::string error_msg;
+ error_msg.assign ("ambiguous command '");
+ error_msg.append(command_cstr);
+ 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(), error_msg.size());
+ }
+ else
+ result.AppendErrorWithFormat ("Unrecognized command '%s'.\n", command_cstr);
+
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ return result.Succeeded();
+}
+
+int
+CommandInterpreter::HandleCompletionMatches (Args &parsed_line,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches)
+{
+ int num_command_matches = 0;
+ bool include_aliases = true;
+ bool look_for_subcommand = false;
+
+ if (cursor_index == -1)
+ {
+ // We got nothing on the command line, so return the list of commands
+ 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), include_aliases, false,
+ &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), include_aliases, false);
+ 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, this,
+ 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);
+
+ 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));
+
+ int num_command_matches;
+
+ matches.Clear();
+
+ // Only max_return_elements == -1 is supported at present:
+ assert (max_return_elements == -1);
+ num_command_matches = HandleCompletionMatches (parsed_line, cursor_index, cursor_char_position, match_start_point,
+ max_return_elements, 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);
+ int partial_name_len = command_partial_str.size();
+
+ // If we matched a unique single command, add a space...
+ if (num_command_matches == 1)
+ {
+ 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;
+}
+
+CommandContext *
+CommandInterpreter::Context ()
+{
+ return &m_current_context;
+}
+
+const Args *
+CommandInterpreter::GetProgramArguments ()
+{
+ if (! HasInterpreterVariables())
+ return NULL;
+
+ VariableMap::const_iterator pos = m_variables.find("run-args");
+ if (pos == m_variables.end())
+ return NULL;
+
+ StateVariable *var = pos->second.get();
+
+ if (var)
+ return &var->GetArgs();
+ return NULL;
+}
+
+const Args *
+CommandInterpreter::GetEnvironmentVariables ()
+{
+ if (! HasInterpreterVariables())
+ return NULL;
+
+ VariableMap::const_iterator pos = m_variables.find("env-vars");
+ if (pos == m_variables.end())
+ return NULL;
+
+ StateVariable *var = pos->second.get();
+ if (var)
+ return &var->GetArgs();
+ return NULL;
+}
+
+
+CommandInterpreter::~CommandInterpreter ()
+{
+}
+
+const char *
+CommandInterpreter::GetPrompt ()
+{
+ VariableMap::iterator pos;
+
+ if (! HasInterpreterVariables())
+ return NULL;
+
+ pos = m_variables.find("prompt");
+ if (pos == m_variables.end())
+ return NULL;
+
+ StateVariable *var = pos->second.get();
+
+ return ((char *) var->GetStringValue());
+}
+
+void
+CommandInterpreter::SetPrompt (const char *new_prompt)
+{
+ VariableMap::iterator pos;
+ CommandReturnObject result;
+
+ if (! HasInterpreterVariables())
+ return;
+
+ pos = m_variables.find ("prompt");
+ if (pos == m_variables.end())
+ return;
+
+ StateVariable *var = pos->second.get();
+
+ if (var->VerifyValue (this, (void *) new_prompt, result))
+ var->SetStringValue (new_prompt);
+}
+
+void
+CommandInterpreter::CrossRegisterCommand (const char * dest_cmd, const char * object_type)
+{
+ CommandObjectSP cmd_obj_sp = GetCommandSP (dest_cmd);
+
+ if (cmd_obj_sp != NULL)
+ {
+ CommandObject *cmd_obj = cmd_obj_sp.get();
+ if (cmd_obj->IsCrossRefObject ())
+ cmd_obj->AddObject (object_type);
+ }
+}
+
+void
+CommandInterpreter::SetScriptLanguage (ScriptLanguage lang)
+{
+ m_script_language = lang;
+}
+
+Listener *
+CommandInterpreter::GetListener ()
+{
+ return m_listener;
+}
+
+SourceManager &
+CommandInterpreter::GetSourceManager ()
+{
+ return m_source_manager;
+}
+
+
+
+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());
+}
+
+bool
+CommandInterpreter::HasInterpreterVariables ()
+{
+ return (!m_variables.empty());
+}
+
+void
+CommandInterpreter::BuildAliasCommandArgs
+(
+ CommandObject *alias_cmd_obj,
+ const char *alias_name,
+ Args &cmd_args,
+ CommandReturnObject &result
+)
+{
+ OptionArgVectorSP option_arg_vector_sp = GetAliasOptions (alias_name);
+
+ if (option_arg_vector_sp.get())
+ {
+ // 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();
+
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+ int old_size = cmd_args.GetArgumentCount();
+ int *used = (int *) malloc ((old_size + 1) * sizeof (int));
+
+ memset (used, 0, (old_size + 1) * sizeof (int));
+ used[0] = 1;
+
+ for (int i = 0; i < option_arg_vector->size(); ++i)
+ {
+ OptionArgPair option_pair = (*option_arg_vector)[i];
+ std::string option = option_pair.first;
+ std::string value = option_pair.second;
+ if (option.compare ("<argument>") == 0)
+ new_args.AppendArgument (value.c_str());
+ else
+ {
+ 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
+ new_args.AppendArgument (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;
+ }
+ else
+ {
+ new_args.AppendArgument (cmd_args.GetArgumentAtIndex (index));
+ used[index] = 1;
+ }
+ }
+ }
+ }
+
+ for (int j = 0; j < cmd_args.GetArgumentCount(); ++j)
+ {
+ if (!used[j])
+ 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.
+ 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)
+{
+ const char *init_file_path = in_cwd ? "./.lldbinit" : "~/.lldbinit";
+ FileSpec init_file (init_file_path);
+ // 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())
+ {
+ char path[PATH_MAX];
+ init_file.GetPath(path, sizeof(path));
+ StreamString source_command;
+ source_command.Printf ("source '%s'", path);
+ HandleCommand (source_command.GetData(), false, result);
+ }
+ else
+ {
+ // nothing to be done if the file doesn't exist
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+}
+
+ScriptInterpreter *
+CommandInterpreter::GetScriptInterpreter ()
+{
+ CommandObject::CommandMap::iterator pos;
+
+ pos = m_command_dict.find ("script");
+ if (pos != m_command_dict.end())
+ {
+ CommandObject *script_cmd_obj = pos->second.get();
+ return ((CommandObjectScript *) script_cmd_obj)->GetInterpreter ();
+ }
+ else
+ return NULL;
+}
+
+
+
+bool
+CommandInterpreter::GetSynchronous ()
+{
+ return m_synchronous_execution;
+}
+
+void
+CommandInterpreter::SetSynchronous (bool value)
+{
+ static bool value_set_once = false;
+ if (!value_set_once)
+ {
+ value_set_once = true;
+ m_synchronous_execution = value;
+ }
+}
+
+void
+CommandInterpreter::OutputFormattedHelpText (Stream &strm,
+ const char *word_text,
+ const char *separator,
+ const char *help_text,
+ uint32_t max_word_len)
+{
+ StateVariable *var = GetStateVariable ("term-width");
+ int max_columns = var->GetIntValue();
+ // Sanity check max_columns, to cope with emacs shell mode with TERM=dumb
+ // (0 rows; 0 columns;).
+ if (max_columns <= 0) max_columns = 80;
+
+ int indent_size = max_word_len + strlen (separator) + 2;
+
+ strm.IndentMore (indent_size);
+
+ int len = indent_size + strlen (help_text) + 1;
+ char *text = (char *) malloc (len);
+ sprintf (text, "%-*s %s %s", max_word_len, word_text, separator, help_text);
+ if (text[len - 1] == '\n')
+ text[--len] = '\0';
+
+ 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;
+ int start = 0;
+ int end = start;
+ int final_end = strlen (text);
+ int sub_len;
+
+ 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--;
+ }
+
+ 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);
+ free (text);
+}
+
+void
+CommandInterpreter::AproposAllSubCommands (CommandObject *cmd_obj, const char *prefix, const char *search_word,
+ StringList &commands_found, StringList &commands_help)
+{
+ CommandObject::CommandMap::const_iterator pos;
+ CommandObject::CommandMap sub_cmd_dict = ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict;
+ CommandObject *sub_cmd_obj;
+
+ for (pos = sub_cmd_dict.begin(); pos != sub_cmd_dict.end(); ++pos)
+ {
+ const char * command_name = pos->first.c_str();
+ 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())
+ AproposAllSubCommands (sub_cmd_obj, complete_command_name.GetData(), search_word, commands_found,
+ commands_help);
+ }
+
+}
+
+void
+CommandInterpreter::FindCommandsForApropos (const char *search_word, StringList &commands_found,
+ StringList &commands_help)
+{
+ CommandObject::CommandMap::const_iterator pos;
+
+ 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())
+ AproposAllSubCommands (cmd_obj, command_name, search_word, commands_found, commands_help);
+
+ }
+}
diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp
new file mode 100644
index 00000000000..080b5b057bf
--- /dev/null
+++ b/lldb/source/Interpreter/CommandObject.cpp
@@ -0,0 +1,448 @@
+//===-- 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/Interpreter/CommandObject.h"
+
+#include <string>
+#include <map>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Options.h"
+
+// These are for the Sourcename completers.
+// FIXME: Make a separate file for the completers.
+#include "lldb/Core/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 (const char *name, const char *help, const char *syntax, uint32_t flags) :
+ m_cmd_name (name),
+ m_cmd_help_short (),
+ m_cmd_help_long (),
+ m_cmd_syntax (),
+ m_flags (flags)
+{
+ 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 ()
+{
+ return m_cmd_syntax.c_str();
+}
+
+const char *
+CommandObject::Translate ()
+{
+ //return m_cmd_func_name.c_str();
+ return "This function is currently not implemented.";
+}
+
+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::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;
+}
+
+Flags&
+CommandObject::GetFlags()
+{
+ return m_flags;
+}
+
+const Flags&
+CommandObject::GetFlags() const
+{
+ return m_flags;
+}
+
+bool
+CommandObject::ExecuteCommandString
+(
+ const char *command_line,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ Args command_args(command_line);
+ return ExecuteWithOptions (command_args, context, interpreter, result);
+}
+
+bool
+CommandObject::ParseOptions
+(
+ Args& args,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ // See if the subclass has options?
+ Options *options = GetOptions();
+ if (options != NULL)
+ {
+ Error error;
+ options->ResetOptionValues();
+
+ // ParseOptions calls getopt_long, 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.Fail() || !options->VerifyOptions (result))
+ {
+ const char *error_cstr = error.AsCString();
+ if (error_cstr)
+ {
+ // We got an error string, lets use that
+ result.GetErrorStream().PutCString(error_cstr);
+ }
+ else
+ {
+ // No error string, output the usage information into result
+ options->GenerateOptionUsage (result.GetErrorStream(), this);
+ }
+ // Set the return status to failed (this was an error).
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ return true;
+}
+bool
+CommandObject::ExecuteWithOptions
+(
+ Args& args,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ for (size_t i = 0; i < args.GetArgumentCount(); ++i)
+ {
+ const char *tmp_str = args.GetArgumentAtIndex (i);
+ if (tmp_str[0] == '`') // back-quote
+ args.ReplaceArgumentAtIndex (i, interpreter->ProcessEmbeddedScriptCommands (tmp_str));
+ }
+
+ Process *process = context->GetExecutionContext().process;
+ if (process == NULL)
+ {
+ if (GetFlags().IsSet(CommandObject::eFlagProcessMustBeLaunched | CommandObject::eFlagProcessMustBePaused))
+ {
+ result.AppendError ("Process must exist.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ StateType state = process->GetState();
+
+ switch (state)
+ {
+
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateSuspended:
+ case eStateCrashed:
+ case eStateStopped:
+ break;
+
+ case eStateDetached:
+ case eStateExited:
+ case eStateUnloaded:
+ if (GetFlags().IsSet(CommandObject::eFlagProcessMustBeLaunched))
+ {
+ result.AppendError ("Process must be launched.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ if (GetFlags().IsSet(CommandObject::eFlagProcessMustBePaused))
+ {
+ result.AppendError ("Process is running. Use 'process interrupt' to pause execution.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ if (!ParseOptions (args, interpreter, result))
+ return false;
+
+ // Call the command-specific version of 'Execute', passing it the already processed arguments.
+ return Execute (args, context, interpreter, result);
+}
+
+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 1;
+
+ size_t found = map_element.first.find (m_match_str, 0);
+ if (found == std::string::npos)
+ return 0;
+ else
+ return found == 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,
+ CommandInterpreter *interpreter,
+ StringList &matches
+)
+{
+ if (WantsRawCommandString())
+ {
+ // 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 will freak out.
+
+ input.AppendArgument ("<FAKE-VALUE>");
+
+ input.ParseArgsForCompletion (*cur_options, opt_element_vector);
+
+ 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,
+ interpreter,
+ 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,
+ interpreter,
+ matches);
+ }
+}
+
+int
+CommandObject::HandleArgumentCompletion
+(
+ Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ StringList &matches
+)
+{
+ return 0;
+}
+
+// Case insensitive version of ::strstr()
+// Returns true if s2 is contained within s1.
+
+static bool
+contains_string (const char *s1, const char *s2)
+{
+ char *locase_s1 = (char *) malloc (strlen (s1) + 1);
+ char *locase_s2 = (char *) malloc (strlen (s2) + 1);
+ int i;
+ for (i = 0; s1 && s1[i] != '\0'; i++)
+ locase_s1[i] = ::tolower (s1[i]);
+ locase_s1[i] = '\0';
+ for (i = 0; s2 && s2[i] != '\0'; i++)
+ locase_s2[i] = ::tolower (s2[i]);
+ locase_s2[i] = '\0';
+
+ const char *result = ::strstr (locase_s1, locase_s2);
+ free (locase_s1);
+ free (locase_s2);
+ // 'result' points into freed memory - but we're not
+ // deref'ing it so hopefully current/future compilers
+ // won't complain..
+
+ if (result == NULL)
+ return false;
+ else
+ return true;
+}
+
+bool
+CommandObject::HelpTextContainsWord (const char *search_word)
+{
+ const char *short_help;
+ const char *long_help;
+ const char *syntax_help;
+ std::string options_usage_help;
+
+
+ bool found_word = false;
+
+ short_help = GetHelp();
+ long_help = GetHelpLong();
+ syntax_help = GetSyntax();
+
+ if (contains_string (short_help, search_word))
+ found_word = true;
+ else if (contains_string (long_help, search_word))
+ found_word = true;
+ else if (contains_string (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 (contains_string (usage_text, search_word))
+ found_word = true;
+ }
+ }
+
+ return found_word;
+}
diff --git a/lldb/source/Interpreter/CommandObjectCrossref.cpp b/lldb/source/Interpreter/CommandObjectCrossref.cpp
new file mode 100644
index 00000000000..27b66379e87
--- /dev/null
+++ b/lldb/source/Interpreter/CommandObjectCrossref.cpp
@@ -0,0 +1,92 @@
+//===-- CommandObjectCrossref.cpp -------------------------------*- 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/CommandObjectCrossref.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectCrossref
+//-------------------------------------------------------------------------
+
+CommandObjectCrossref::CommandObjectCrossref
+(
+ const char *name,
+ const char *help,
+ const char *syntax
+) :
+ CommandObject (name, help, syntax),
+ m_crossref_object_types()
+{
+}
+
+CommandObjectCrossref::~CommandObjectCrossref ()
+{
+}
+
+bool
+CommandObjectCrossref::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ if (m_crossref_object_types.GetArgumentCount() == 0)
+ {
+ result.AppendErrorWithFormat ("There are no objects for which you can call '%s'.\n", GetCommandName());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ GenerateHelpText (result);
+ }
+ return result.Succeeded();
+}
+
+void
+CommandObjectCrossref::AddObject (const char *obj_name)
+{
+ m_crossref_object_types.AppendArgument (obj_name);
+}
+
+const char **
+CommandObjectCrossref::GetObjectTypes () const
+{
+ return m_crossref_object_types.GetConstArgumentVector();
+}
+
+void
+CommandObjectCrossref::GenerateHelpText (CommandReturnObject &result)
+{
+ result.AppendMessage ("This command can be called on the following types of objects:");
+
+ for (int i = 0; i < m_crossref_object_types.GetArgumentCount(); ++i)
+ {
+ const char *obj_name = m_crossref_object_types.GetArgumentAtIndex(i);
+ result.AppendMessageWithFormat (" %s (e.g. '%s %s')\n", obj_name,
+ obj_name, GetCommandName());
+ }
+
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+}
+
+bool
+CommandObjectCrossref::IsCrossRefObject ()
+{
+ return true;
+}
diff --git a/lldb/source/Interpreter/CommandObjectMultiword.cpp b/lldb/source/Interpreter/CommandObjectMultiword.cpp
new file mode 100644
index 00000000000..874be0ea6a1
--- /dev/null
+++ b/lldb/source/Interpreter/CommandObjectMultiword.cpp
@@ -0,0 +1,263 @@
+//===-- 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/Interpreter/CommandObjectMultiword.h"
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandContext.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiword
+//-------------------------------------------------------------------------
+
+CommandObjectMultiword::CommandObjectMultiword
+(
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags
+) :
+ CommandObject (name, help, syntax, flags)
+{
+}
+
+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())
+ 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 (CommandObjectSP cmd_obj, const char *name,
+ CommandInterpreter *interpreter)
+{
+ CommandMap::iterator pos;
+ bool success = true;
+
+ pos = m_subcommand_dict.find(name);
+ if (pos == m_subcommand_dict.end())
+ {
+ m_subcommand_dict[name] = cmd_obj;
+ interpreter->CrossRegisterCommand (name, GetCommandName());
+ }
+ else
+ success = false;
+
+ return success;
+}
+
+bool
+CommandObjectMultiword::Execute
+(
+ Args& args,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ const size_t argc = args.GetArgumentCount();
+ if (argc == 0)
+ {
+ GenerateHelpText (result, interpreter);
+ }
+ else
+ {
+ const char *sub_command = args.GetArgumentAtIndex (0);
+
+ if (sub_command)
+ {
+ if (::strcasecmp (sub_command, "help") == 0)
+ {
+ GenerateHelpText (result, interpreter);
+ }
+ 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->ExecuteWithOptions (args, context, interpreter, result);
+ }
+ else
+ {
+ std::string error_msg;
+ int 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 (int 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(), error_msg.size());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' does not have any subcommands.\n", GetCommandName());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+
+ return result.Succeeded();
+}
+
+void
+CommandObjectMultiword::GenerateHelpText (CommandReturnObject &result, CommandInterpreter *interpreter)
+{
+ // First time through here, generate the help text for the object and
+ // push it to the return result object as well
+
+ StreamString &output_stream = result.GetOutputStream();
+ output_stream.PutCString ("The following subcommands are supported:\n\n");
+
+ CommandMap::iterator pos;
+ std::string longest_word = interpreter->FindLongestCommandWord (m_subcommand_dict);
+ uint32_t max_len = 0;
+
+ if (! longest_word.empty())
+ max_len = strlen (longest_word.c_str()) + 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);
+ interpreter->OutputFormattedHelpText (result.GetOutputStream(), indented_command.c_str(), "--",
+ pos->second->GetHelp(), max_len);
+ }
+
+ output_stream.PutCString ("\nFor more help on any particular subcommand, type 'help <command> <subcommand>'.\n");
+
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+}
+
+int
+CommandObjectMultiword::HandleCompletion
+(
+ Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ CommandInterpreter *interpreter,
+ StringList &matches
+)
+{
+ 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, interpreter, 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, interpreter, matches);
+ }
+
+ }
+}
+
diff --git a/lldb/source/Interpreter/CommandObjectRegexCommand.cpp b/lldb/source/Interpreter/CommandObjectRegexCommand.cpp
new file mode 100644
index 00000000000..b3fa6a41d97
--- /dev/null
+++ b/lldb/source/Interpreter/CommandObjectRegexCommand.cpp
@@ -0,0 +1,123 @@
+//===-- 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/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
+(
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t max_matches
+) :
+ CommandObject (name, help, syntax),
+ m_entries(),
+ m_max_matches (max_matches)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommandObjectRegexCommand::~CommandObjectRegexCommand()
+{
+}
+
+
+bool
+CommandObjectRegexCommand::Execute
+(
+ Args& command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ return false;
+}
+
+
+bool
+CommandObjectRegexCommand::ExecuteRawCommandString
+(
+ const char *command,
+ CommandContext *context,
+ CommandInterpreter *interpreter,
+ CommandReturnObject &result
+)
+{
+ if (command)
+ {
+ EntryCollection::const_iterator pos, end = m_entries.end();
+ for (pos = m_entries.begin(); pos != end; ++pos)
+ {
+ if (pos->regex.Execute (command, m_max_matches))
+ {
+ 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 (pos->regex.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_options.verbose)
+// result.GetOutputStream().Printf("%s\n", new_command.c_str());
+ return interpreter->HandleCommand(new_command.c_str(), true, result);
+ }
+ }
+ result.SetStatus(eReturnStatusFailed);
+ 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 exression 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;
+}
diff --git a/lldb/source/Interpreter/CommandReturnObject.cpp b/lldb/source/Interpreter/CommandReturnObject.cpp
new file mode 100644
index 00000000000..f634e3c7df5
--- /dev/null
+++ b/lldb/source/Interpreter/CommandReturnObject.cpp
@@ -0,0 +1,175 @@
+//===-- 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/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandReturnObject::CommandReturnObject () :
+ m_output_stream (),
+ m_error_stream (),
+ m_status (eReturnStatusStarted),
+ m_did_change_process_state (false)
+{
+}
+
+CommandReturnObject::~CommandReturnObject ()
+{
+}
+
+StreamString &
+CommandReturnObject::GetOutputStream ()
+{
+ return m_output_stream;
+}
+
+StreamString &
+CommandReturnObject::GetErrorStream ()
+{
+ return m_error_stream;
+}
+
+void
+CommandReturnObject::AppendErrorWithFormat (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ StreamString sstrm;
+ sstrm.PrintfVarArg(format, args);
+ va_end (args);
+
+ m_error_stream.Printf("error: %s", sstrm.GetData());
+}
+
+
+void
+CommandReturnObject::AppendMessageWithFormat (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ StreamString sstrm;
+ sstrm.PrintfVarArg(format, args);
+ va_end (args);
+
+ m_output_stream.Printf("%s", sstrm.GetData());
+}
+
+void
+CommandReturnObject::AppendWarningWithFormat (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ StreamString sstrm;
+ sstrm.PrintfVarArg(format, args);
+ va_end (args);
+
+ m_error_stream.Printf("warning: %s", sstrm.GetData());
+}
+
+void
+CommandReturnObject::AppendMessage (const char *in_string, int len)
+{
+ if (len < 0)
+ len = ::strlen (in_string);
+ m_output_stream.Printf("%*.*s\n", len, len, in_string);
+}
+
+void
+CommandReturnObject::AppendWarning (const char *in_string, int len)
+{
+ if (len < 0)
+ len = ::strlen (in_string);
+ m_error_stream.Printf("warning: %*.*s\n", len, len, 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, int len)
+{
+ if (len < 0)
+ len = ::strlen (in_string);
+ m_error_stream.Printf("%*.*s", len, len, in_string);
+}
+
+void
+CommandReturnObject::AppendError (const char *in_string, int len)
+{
+ if (!in_string)
+ return;
+
+ if (len < 0)
+ len = ::strlen (in_string);
+ m_error_stream.Printf ("error: %*.*s\n", len, len, in_string);
+}
+
+// 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, int len)
+{
+ if (len < 0)
+ len = ::strlen (in_string);
+ m_error_stream.Printf ("%*.*s", len, len, 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()
+{
+ m_output_stream.Clear();
+ m_error_stream.Clear();
+ m_status = eReturnStatusStarted;
+}
+
+bool
+CommandReturnObject::GetDidChangeProcessState ()
+{
+ return m_did_change_process_state;
+}
+
+void
+CommandReturnObject::SetDidChangeProcessState (bool b)
+{
+ m_did_change_process_state = b;
+}
+
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
new file mode 100644
index 00000000000..fa3ac31e691
--- /dev/null
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -0,0 +1,66 @@
+//===-- 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/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 "PseudoTerminal.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ScriptInterpreter::ScriptInterpreter (ScriptLanguage script_lang) :
+ m_script_lang (script_lang),
+ m_interpreter_pty ()
+{
+ if (m_interpreter_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, NULL, 0))
+ {
+ const char *slave_name = m_interpreter_pty.GetSlaveName(NULL, 0);
+ if (slave_name)
+ m_pty_slave_name.assign(slave_name);
+ }
+}
+
+ScriptInterpreter::~ScriptInterpreter ()
+{
+ m_interpreter_pty.CloseMasterFileDescriptor();
+}
+
+const char *
+ScriptInterpreter::GetScriptInterpreterPtyName ()
+{
+ return m_pty_slave_name.c_str();
+}
+
+int
+ScriptInterpreter::GetMasterFileDescriptor ()
+{
+ return m_interpreter_pty.GetMasterFileDescriptor();
+}
+
+void
+ScriptInterpreter::CollectDataForBreakpointCommandCallback
+(
+ BreakpointOptions *bp_options,
+ CommandReturnObject &result
+)
+{
+ result.SetStatus (eReturnStatusFailed);
+ result.AppendError ("ScriptInterpreter::GetScriptCommands(StringList &) is not implemented.");
+}
+
+
diff --git a/lldb/source/Interpreter/ScriptInterpreterNone.cpp b/lldb/source/Interpreter/ScriptInterpreterNone.cpp
new file mode 100644
index 00000000000..cdc399e7d86
--- /dev/null
+++ b/lldb/source/Interpreter/ScriptInterpreterNone.cpp
@@ -0,0 +1,38 @@
+//===-- 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/Interpreter/ScriptInterpreterNone.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StringList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ScriptInterpreterNone::ScriptInterpreterNone () :
+ ScriptInterpreter (eScriptLanguageNone)
+{
+}
+
+ScriptInterpreterNone::~ScriptInterpreterNone ()
+{
+}
+
+void
+ScriptInterpreterNone::ExecuteOneLine (const std::string &line, FILE *out, FILE *err)
+{
+ ::fprintf (err, "error: there is no embedded script interpreter in this mode.\n");
+}
+
+void
+ScriptInterpreterNone::ExecuteInterpreterLoop (FILE *out, FILE *err)
+{
+ fprintf (err, "error: there is no embedded script interpreter in this mode.\n");
+}
+
+
diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp
new file mode 100644
index 00000000000..6b2e3b2e7ad
--- /dev/null
+++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp
@@ -0,0 +1,830 @@
+//===-- 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:
+
+#include <Python.h>
+
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+
+
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Process.h"
+
+extern "C" void init_lldb (void);
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char embedded_interpreter_string[] =
+"import readline\n\
+import code\n\
+import sys\n\
+import traceback\n\
+\n\
+class SimpleREPL(code.InteractiveConsole):\n\
+ def __init__(self, prompt, dict):\n\
+ code.InteractiveConsole.__init__(self,dict)\n\
+ self.prompt = prompt\n\
+ self.loop_exit = False\n\
+ self.dict = dict\n\
+\n\
+ def interact(self):\n\
+ try:\n\
+ sys.ps1\n\
+ except AttributeError:\n\
+ sys.ps1 = \">>> \"\n\
+ try:\n\
+ sys.ps2\n\
+ except AttributeError:\n\
+ sys.ps2 = \"... \"\n\
+\n\
+ while not self.loop_exit:\n\
+ try:\n\
+ self.read_py_command()\n\
+ except (SystemExit, EOFError):\n\
+ # EOF while in Python just breaks out to top level.\n\
+ self.write('\\n')\n\
+ self.loop_exit = True\n\
+ break\n\
+ except KeyboardInterrupt:\n\
+ self.write(\"\\nKeyboardInterrupt\\n\")\n\
+ self.resetbuffer()\n\
+ more = 0\n\
+ except:\n\
+ traceback.print_exc()\n\
+\n\
+ def process_input (self, in_str):\n\
+ # Canonicalize the format of the input string\n\
+ temp_str = in_str\n\
+ temp_str.strip(' \t')\n\
+ words = temp_str.split()\n\
+ temp_str = ('').join(words)\n\
+\n\
+ # Check the input string to see if it was the quit\n\
+ # command. If so, intercept it, so that it doesn't\n\
+ # close stdin on us!\n\
+ if (temp_str.lower() == \"quit()\"):\n\
+ self.loop_exit = True\n\
+ in_str = \"raise SystemExit \"\n\
+ return in_str\n\
+\n\
+ def my_raw_input (self, prompt):\n\
+ stream = sys.stdout\n\
+ stream.write (prompt)\n\
+ stream.flush ()\n\
+ try:\n\
+ line = sys.stdin.readline()\n\
+ except KeyboardInterrupt:\n\
+ line = \" \\n\"\n\
+ except (SystemExit, EOFError):\n\
+ line = \"quit()\\n\"\n\
+ if not line:\n\
+ raise EOFError\n\
+ if line[-1] == '\\n':\n\
+ line = line[:-1]\n\
+ return line\n\
+\n\
+ def read_py_command(self):\n\
+ # Read off a complete Python command.\n\
+ more = 0\n\
+ while 1:\n\
+ if more:\n\
+ prompt = sys.ps2\n\
+ else:\n\
+ prompt = sys.ps1\n\
+ line = self.my_raw_input(prompt)\n\
+ # Can be None if sys.stdin was redefined\n\
+ encoding = getattr(sys.stdin, \"encoding\", None)\n\
+ if encoding and not isinstance(line, unicode):\n\
+ line = line.decode(encoding)\n\
+ line = self.process_input (line)\n\
+ more = self.push(line)\n\
+ if not more:\n\
+ break\n\
+\n\
+def run_python_interpreter (dict):\n\
+ # Pass in the dictionary, for continuity from one session to the next.\n\
+ repl = SimpleREPL('>>> ', dict)\n\
+ repl.interact()\n";
+
+static int
+_check_and_flush (FILE *stream)
+{
+ int prev_fail = ferror (stream);
+ return fflush (stream) || prev_fail ? EOF : 0;
+}
+
+ScriptInterpreterPython::ScriptInterpreterPython () :
+ ScriptInterpreter (eScriptLanguagePython),
+ m_compiled_module (NULL),
+ m_termios_valid (false)
+{
+
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+ // Find the module that owns this code and use that path we get to
+ // set the PYTHONPATH appropriately.
+
+ FileSpec this_module (Host::GetModuleFileSpecForHostAddress ((void *)init_lldb));
+ std::string python_path;
+
+ if (this_module.GetDirectory())
+ {
+ // Append the directory that the module that loaded this code
+ // belongs to
+ python_path += this_module.GetDirectory().AsCString("");
+
+#if defined (__APPLE__)
+ // If we are running on MacOSX we might be in a framework and should
+ // add an appropriate path so Resource can be found in a bundle
+
+ if (::strstr(this_module.GetDirectory().AsCString(""), ".framework"))
+ {
+ python_path.append(1, ':');
+ python_path.append(this_module.GetDirectory().AsCString(""));
+ python_path.append("/Resources/Python");
+ }
+#endif
+ // The the PYTHONPATH environment variable so that Python can find
+ // our lldb.py module and our _lldb.so.
+ ::setenv ("PYTHONPATH", python_path.c_str(), 1);
+ }
+
+ Py_Initialize ();
+
+ PyObject *compiled_module = Py_CompileString (embedded_interpreter_string, "embedded_interpreter.py",
+ Py_file_input);
+
+ m_compiled_module = compiled_module;
+
+ init_lldb ();
+
+ // Update the path python uses to search for modules to include the current directory.
+
+ int success = PyRun_SimpleString ("import sys");
+ success = PyRun_SimpleString ("sys.path.append ('.')");
+ if (success == 0)
+ {
+ // Import the Script Bridge module.
+ success = PyRun_SimpleString ("from lldb import *");
+ }
+
+ const char *pty_slave_name = GetScriptInterpreterPtyName ();
+ FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle();
+
+ PyObject *pmod = PyImport_ExecCodeModule((char *)"embedded_interpreter", m_compiled_module);
+ if (pmod != NULL)
+ {
+ PyRun_SimpleString ("ConsoleDict = locals()");
+ PyRun_SimpleString ("from embedded_interpreter import run_python_interpreter");
+ PyRun_SimpleString ("import sys");
+ PyRun_SimpleString ("from termios import *");
+ PyRun_SimpleString ("old_stdin = sys.stdin");
+
+ StreamString run_string;
+ run_string.Printf ("new_stdin = open('%s', 'r')", pty_slave_name);
+ PyRun_SimpleString (run_string.GetData());
+ PyRun_SimpleString ("sys.stdin = new_stdin");
+
+ PyRun_SimpleString ("old_stdout = sys.stdout");
+
+ if (out_fh != NULL)
+ {
+ PyObject *new_sysout = PyFile_FromFile (out_fh, (char *) "", (char *) "w",
+ _check_and_flush);
+ PyObject *sysmod = PyImport_AddModule ("sys");
+ PyObject *sysdict = PyModule_GetDict (sysmod);
+
+ if ((new_sysout != NULL)
+ && (sysmod != NULL)
+ && (sysdict != NULL))
+ {
+ PyDict_SetItemString (sysdict, "stdout", new_sysout);
+ }
+
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ }
+
+ PyRun_SimpleString ("new_mode = tcgetattr(new_stdin)");
+ PyRun_SimpleString ("new_mode[3] = new_mode[3] | ECHO | ICANON");
+ PyRun_SimpleString ("new_mode[6][VEOF] = 255");
+ PyRun_SimpleString ("tcsetattr (new_stdin, TCSANOW, new_mode)");
+ }
+
+
+}
+
+ScriptInterpreterPython::~ScriptInterpreterPython ()
+{
+ PyRun_SimpleString ("sys.stdin = old_stdin");
+ PyRun_SimpleString ("sys.stdout = old_stdout");
+ Py_Finalize ();
+}
+
+void
+ScriptInterpreterPython::ExecuteOneLine (const std::string& line, FILE *out, FILE *err)
+{
+ int success;
+
+ success = PyRun_SimpleString (line.c_str());
+ if (success != 0)
+ {
+ fprintf (err, "error: python failed attempting to evaluate '%s'\n", line.c_str());
+ }
+}
+
+
+
+size_t
+ScriptInterpreterPython::InputReaderCallback
+(
+ void *baton,
+ InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ if (baton == NULL)
+ return 0;
+
+ ScriptInterpreterPython *interpreter = (ScriptInterpreterPython *) baton;
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ {
+ // Save terminal settings if we can
+ interpreter->m_termios_valid = ::tcgetattr (::fileno (reader->GetInputFileHandle()),
+ &interpreter->m_termios) == 0;
+ struct termios tmp_termios;
+ if (::tcgetattr (::fileno (reader->GetInputFileHandle()), &tmp_termios) == 0)
+ {
+ tmp_termios.c_cc[VEOF] = _POSIX_VDISABLE;
+ ::tcsetattr (::fileno (reader->GetInputFileHandle()), TCSANOW, &tmp_termios);
+ }
+ }
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderReactivate:
+ break;
+
+ case eInputReaderGotToken:
+ if (bytes && bytes_len)
+ {
+ if ((int) bytes[0] == 4)
+ ::write (interpreter->GetMasterFileDescriptor(), "quit()", 6);
+ else
+ ::write (interpreter->GetMasterFileDescriptor(), bytes, bytes_len);
+ }
+ ::write (interpreter->GetMasterFileDescriptor(), "\n", 1);
+ break;
+
+ case eInputReaderDone:
+ // Send a control D to the script interpreter
+ //::write (interpreter->GetMasterFileDescriptor(), "\nquit()\n", strlen("\nquit()\n"));
+ // Write a newline out to the reader output
+ //::fwrite ("\n", 1, 1, out_fh);
+ // Restore terminal settings if they were validly saved
+ if (interpreter->m_termios_valid)
+ {
+ ::tcsetattr (::fileno (reader->GetInputFileHandle()),
+ TCSANOW,
+ &interpreter->m_termios);
+ }
+ break;
+ }
+
+ return bytes_len;
+}
+
+
+void
+ScriptInterpreterPython::ExecuteInterpreterLoop (FILE *out, FILE *err)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ InputReaderSP reader_sp (new InputReader());
+ 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::GetSharedInstance().PushInputReader (reader_sp);
+ ExecuteOneLine ("run_python_interpreter(ConsoleDict)", out, err);
+ Debugger::GetSharedInstance().PopInputReader (reader_sp);
+ }
+ }
+}
+
+bool
+ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string,
+ ScriptInterpreter::ReturnType return_type,
+ void *ret_value)
+{
+ PyObject *py_return = NULL;
+ PyObject *mainmod = PyImport_AddModule ("__main__");
+ PyObject *globals = PyModule_GetDict (mainmod);
+ PyObject *locals = globals;
+ PyObject *py_error = NULL;
+ bool ret_success;
+ int success;
+
+ if (in_string != 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 (py_return != NULL)
+ {
+ switch (return_type)
+ {
+ case eCharPtr: // "char *"
+ {
+ const char format[3] = "s#";
+ success = PyArg_Parse (py_return, format, (char **) &ret_value);
+ break;
+ }
+ case eBool:
+ {
+ const char format[2] = "b";
+ success = PyArg_Parse (py_return, format, (bool *) ret_value);
+ break;
+ }
+ case eShortInt:
+ {
+ const char format[2] = "h";
+ success = PyArg_Parse (py_return, format, (short *) ret_value);
+ break;
+ }
+ case eShortIntUnsigned:
+ {
+ const char format[2] = "H";
+ success = PyArg_Parse (py_return, format, (unsigned short *) ret_value);
+ break;
+ }
+ case eInt:
+ {
+ const char format[2] = "i";
+ success = PyArg_Parse (py_return, format, (int *) ret_value);
+ break;
+ }
+ case eIntUnsigned:
+ {
+ const char format[2] = "I";
+ success = PyArg_Parse (py_return, format, (unsigned int *) ret_value);
+ break;
+ }
+ case eLongInt:
+ {
+ const char format[2] = "l";
+ success = PyArg_Parse (py_return, format, (long *) ret_value);
+ break;
+ }
+ case eLongIntUnsigned:
+ {
+ const char format[2] = "k";
+ success = PyArg_Parse (py_return, format, (unsigned long *) ret_value);
+ break;
+ }
+ case eLongLong:
+ {
+ const char format[2] = "L";
+ success = PyArg_Parse (py_return, format, (long long *) ret_value);
+ break;
+ }
+ case eLongLongUnsigned:
+ {
+ const char format[2] = "K";
+ success = PyArg_Parse (py_return, format, (unsigned long long *) ret_value);
+ break;
+ }
+ case eFloat:
+ {
+ const char format[2] = "f";
+ success = PyArg_Parse (py_return, format, (float *) ret_value);
+ break;
+ }
+ case eDouble:
+ {
+ const char format[2] = "d";
+ success = PyArg_Parse (py_return, format, (double *) ret_value);
+ break;
+ }
+ case eChar:
+ {
+ const char format[2] = "c";
+ success = PyArg_Parse (py_return, format, (char *) ret_value);
+ break;
+ }
+ default:
+ {}
+ }
+ Py_DECREF (py_return);
+ if (success)
+ ret_success = true;
+ else
+ ret_success = false;
+ }
+ }
+
+ py_error = PyErr_Occurred();
+ if (py_error != NULL)
+ {
+ if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError))
+ PyErr_Print ();
+ PyErr_Clear();
+ ret_success = false;
+ }
+
+ return ret_success;
+}
+
+bool
+ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string)
+{
+ bool success = false;
+ PyObject *py_return = NULL;
+ PyObject *mainmod = PyImport_AddModule ("__main__");
+ PyObject *globals = PyModule_GetDict (mainmod);
+ PyObject *locals = globals;
+ PyObject *py_error = NULL;
+
+ 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)
+ {
+ py_return = PyEval_EvalCode (compiled_code, globals, locals);
+ if (py_return != NULL)
+ {
+ success = true;
+ Py_DECREF (py_return);
+ }
+ }
+ }
+ }
+
+ py_error = PyErr_Occurred ();
+ if (py_error != NULL)
+ {
+ if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError))
+ PyErr_Print ();
+ PyErr_Clear();
+ success = false;
+ }
+
+ return success;
+}
+
+static const char *g_reader_instructions = "Enter your Python command(s). Type 'DONE' to end.";
+
+size_t
+ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback
+(
+ void *baton,
+ InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ static StringList commands_in_progress;
+
+ FILE *out_fh = reader->GetOutputFileHandle();
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ {
+ commands_in_progress.Clear();
+ if (out_fh)
+ {
+ ::fprintf (out_fh, "%s\n", g_reader_instructions);
+ if (reader->GetPrompt())
+ ::fprintf (out_fh, "%s", reader->GetPrompt());
+ }
+ }
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderReactivate:
+ if (reader->GetPrompt() && out_fh)
+ ::fprintf (out_fh, "%s", reader->GetPrompt());
+ break;
+
+ case eInputReaderGotToken:
+ {
+ std::string temp_string (bytes, bytes_len);
+ commands_in_progress.AppendString (temp_string.c_str());
+ if (out_fh && !reader->IsDone() && reader->GetPrompt())
+ ::fprintf (out_fh, "%s", reader->GetPrompt());
+ }
+ break;
+
+ case eInputReaderDone:
+ {
+ BreakpointOptions *bp_options = (BreakpointOptions *)baton;
+ std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
+ data_ap->user_source.AppendList (commands_in_progress);
+ if (data_ap.get())
+ {
+ ScriptInterpreter *interpreter = Debugger::GetSharedInstance().GetCommandInterpreter().GetScriptInterpreter();
+ if (interpreter)
+ {
+ if (interpreter->GenerateBreakpointCommandCallbackData (data_ap->user_source,
+ data_ap->script_source))
+ {
+ if (data_ap->script_source.GetSize() == 1)
+ {
+ BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
+ bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp);
+ }
+ }
+ }
+ else
+ {
+ // FIXME: Error processing.
+ }
+ }
+ }
+ break;
+
+ }
+
+ return bytes_len;
+}
+
+void
+ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CommandReturnObject &result)
+{
+ InputReaderSP reader_sp (new InputReader ());
+
+ 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::GetSharedInstance().PushInputReader (reader_sp);
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+}
+
+bool
+ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &function_def)
+{
+ // Convert StringList to one long, newline delimited, const char *.
+ std::string function_def_string;
+
+ int num_lines = function_def.GetSize();
+
+ for (int i = 0; i < num_lines; ++i)
+ {
+ function_def_string.append (function_def.GetStringAtIndex(i));
+ if (function_def_string.at (function_def_string.length() - 1) != '\n')
+ function_def_string.append ("\n");
+
+ }
+
+ return ExecuteMultipleLines (function_def_string.c_str());
+}
+
+bool
+ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user_input, StringList &callback_data)
+{
+ static int num_created_functions = 0;
+
+ user_input.RemoveBlankLines ();
+ int num_lines = user_input.GetSize();
+ std::string last_function_call;
+
+ // Go through lines of input looking for any function definitions. For each function definition found,
+ // export the function definition to Python, create a potential function call for the function, and
+ // mark the lines of the function to be removed from the user input.
+
+ for (int i = 0; i < num_lines; ++i)
+ {
+ int function_start = i;
+ std::string current_str = user_input.GetStringAtIndex (i);
+ const char *current_line = current_str.c_str();
+ int len = 0;
+ if (current_line)
+ len = strlen (current_line);
+
+ // Check to see if the current line is the start of a Python function definition.
+ if (len > 4 && strncmp (current_line, "def ", 4) == 0)
+ {
+ // We've found the first line of a function. First, get the function name.
+
+ // Skip over the 'def '.
+ char *start = (char *) current_line + 4;
+
+ // Skip over white space.
+ while (start[0] == ' ' || start[0] == '\t')
+ ++start;
+
+ // Find the end of the function name.
+ char *end = start;
+ while (isalnum (end[0]) || end[0] == '_')
+ ++end;
+
+ int name_len = end - start;
+ std::string func_name = current_str.substr (4, name_len);
+
+ // Now to find the last line of the function. That will be the first line that does not begin with
+ // any white space (thanks to Python's indentation rules).
+ ++i;
+ bool found = false;
+ while (i < num_lines && !found)
+ {
+ std::string next_str = user_input.GetStringAtIndex (i);
+ const char *next_line = next_str.c_str();
+ if (next_line[0] != ' ' && next_line[0] != '\t')
+ found = true;
+ else
+ ++i;
+ }
+ if (found)
+ --i; // Make 'i' correspond to the last line of the function.
+ int function_end = i;
+
+ // Special case: All of user_input is one big function definition.
+ if ((function_start == 0) && (function_end == (num_lines - 1)))
+ {
+ ExportFunctionDefinitionToInterpreter (user_input);
+ last_function_call = func_name + " ()";
+ callback_data.AppendString (last_function_call.c_str());
+ return callback_data.GetSize() > 0;
+ }
+ else
+ {
+ // Make a copy of the function definition:
+ StringList new_function;
+ for (int k = function_start; k <= function_end; ++k)
+ {
+ new_function.AppendString (user_input.GetStringAtIndex (k));
+ // Mark the string to be deleted from user_input.
+ user_input.DeleteStringAtIndex (k);
+ user_input.InsertStringAtIndex (k, "<lldb_delete>");
+ }
+ ExportFunctionDefinitionToInterpreter (new_function);
+ last_function_call = func_name + " ()";
+ }
+ }
+ }
+
+ // Now instead of trying to really delete the marked lines from user_input, we will just copy all the
+ // unmarked lines into a new StringList.
+
+ StringList new_user_input;
+
+ for (int i = 0; i < num_lines; ++i)
+ {
+ std::string current_string = user_input.GetStringAtIndex (i);
+ if (current_string.compare (0, 13, "<lldb_delete>") == 0)
+ continue;
+
+ new_user_input.AppendString (current_string.c_str());
+ }
+
+ num_lines = new_user_input.GetSize();
+
+ if (num_lines > 0)
+ {
+ if (num_lines == 1
+ && strchr (new_user_input.GetStringAtIndex(0), '\n') == NULL)
+ {
+ // If there's only one line of input, and it doesn't contain any newline characters....
+ callback_data.AppendString (new_user_input.GetStringAtIndex (0));
+ }
+ else
+ {
+ // Create the new function name.
+ StreamString func_name;
+ func_name.Printf ("lldb_bp_callback_func_%d", num_created_functions);
+ //std::string func_name = "lldb_bp_callback_func_" + num_created_functions;
+ ++num_created_functions;
+
+ // Create the function call for the new function.
+ last_function_call = func_name.GetString() + " ()";
+
+ // Create the Python function definition line (which will have to be inserted at the beginning of
+ // the function).
+ std::string def_line = "def " + func_name.GetString() + " ():";
+
+
+ // Indent all lines an additional four spaces (as they are now being put inside a function definition).
+ for (int i = 0; i < num_lines; ++i)
+ {
+ const char *temp_cstring = new_user_input.GetStringAtIndex(i);
+ std::string temp2 = " ";
+ temp2.append(temp_cstring);
+ new_user_input.DeleteStringAtIndex (i);
+ new_user_input.InsertStringAtIndex (i, temp2.c_str());
+ }
+
+ // Insert the function definition line at the top of the new function.
+ new_user_input.InsertStringAtIndex (0, def_line.c_str());
+
+ ExportFunctionDefinitionToInterpreter (new_user_input);
+ callback_data.AppendString (last_function_call.c_str());
+ }
+ }
+ else
+ {
+ if (!last_function_call.empty())
+ callback_data.AppendString (last_function_call.c_str());
+ }
+
+ return callback_data.GetSize() > 0;
+}
+
+bool
+ScriptInterpreterPython::BreakpointCallbackFunction
+(
+ void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id
+)
+{
+ bool ret_value = true;
+ bool temp_bool;
+
+ BreakpointOptions::CommandData *bp_option_data = (BreakpointOptions::CommandData *) baton;
+
+ const char *python_string = bp_option_data->script_source.GetStringAtIndex(0);
+
+ if (python_string != NULL)
+ {
+ bool success =
+ Debugger::GetSharedInstance().GetCommandInterpreter().GetScriptInterpreter()->ExecuteOneLineWithReturn
+ (python_string,
+ ScriptInterpreter::eBool,
+ (void *) &temp_bool);
+ if (success)
+ ret_value = temp_bool;
+ }
+
+ return ret_value;
+}
diff --git a/lldb/source/Interpreter/StateVariable.cpp b/lldb/source/Interpreter/StateVariable.cpp
new file mode 100644
index 00000000000..3f3c3fdb1e0
--- /dev/null
+++ b/lldb/source/Interpreter/StateVariable.cpp
@@ -0,0 +1,320 @@
+//===-- StateVariable.cpp ---------------------------------------*- 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"
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+
+#include "lldb/Interpreter/StateVariable.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Variables with integer values.
+
+StateVariable::StateVariable
+(
+ const char *name,
+ int value,
+ const char *help,
+ Callback func_ptr
+) :
+ m_name (name),
+ m_type (eTypeInteger),
+ m_help_text (help),
+ m_verification_func_ptr (func_ptr)
+{
+ m_int_value = value;
+}
+
+// Variables with boolean values.
+
+StateVariable::StateVariable
+(
+ const char *name,
+ bool value,
+ const char *help,
+ Callback func_ptr
+ ) :
+ m_name (name),
+ m_type (eTypeBoolean),
+ m_help_text (help),
+ m_verification_func_ptr (func_ptr)
+{
+ m_int_value = value;
+}
+
+// Variables with string values.
+
+StateVariable::StateVariable
+(
+ const char *name,
+ const char *value,
+ bool can_append,
+ const char *help,
+ Callback func_ptr
+ ) :
+ m_name (name),
+ m_type (eTypeString),
+ m_int_value (0),
+ m_string_values (),
+ m_help_text (help),
+ m_verification_func_ptr (func_ptr)
+{
+ m_string_values.AppendArgument(value);
+}
+
+// Variables with array of strings values.
+
+StateVariable::StateVariable
+(
+ const char *name,
+ const Args *args,
+ const char *help,
+ Callback func_ptr
+ ) :
+ m_name (name),
+ m_type (eTypeStringArray),
+ m_help_text (help),
+ m_string_values(),
+ m_verification_func_ptr (func_ptr)
+{
+ if (args)
+ m_string_values = *args;
+}
+
+StateVariable::~StateVariable ()
+{
+}
+
+const char *
+StateVariable::GetName () const
+{
+ return m_name.c_str();
+}
+
+StateVariable::Type
+StateVariable::GetType () const
+{
+ return m_type;
+}
+
+int
+StateVariable::GetIntValue () const
+{
+ return m_int_value;
+}
+
+bool
+StateVariable::GetBoolValue () const
+{
+ return m_int_value;
+}
+
+const char *
+StateVariable::GetStringValue () const
+{
+ return m_string_values.GetArgumentAtIndex(0);
+}
+
+const Args &
+StateVariable::GetArgs () const
+{
+ return m_string_values;
+}
+
+Args &
+StateVariable::GetArgs ()
+{
+ return m_string_values;
+}
+
+const char *
+StateVariable::GetHelp () const
+{
+ return m_help_text.c_str();
+}
+
+void
+StateVariable::SetHelp (const char *help)
+{
+ m_help_text = help;
+}
+
+void
+StateVariable::AppendVariableInformation (CommandReturnObject &result)
+{
+ switch (m_type)
+ {
+ case eTypeBoolean:
+ if (m_int_value)
+ result.AppendMessageWithFormat (" %s (bool) = True\n", m_name.c_str());
+ else
+ result.AppendMessageWithFormat (" %s (bool) = False\n", m_name.c_str());
+ break;
+
+ case eTypeInteger:
+ result.AppendMessageWithFormat (" %s (int) = %d\n", m_name.c_str(), m_int_value);
+ break;
+
+ case eTypeString:
+ {
+ const char *cstr = m_string_values.GetArgumentAtIndex(0);
+ if (cstr && cstr[0])
+ result.AppendMessageWithFormat (" %s (str) = '%s'\n", m_name.c_str(), cstr);
+ else
+ result.AppendMessageWithFormat (" %s (str) = <no value>\n", m_name.c_str());
+ }
+ break;
+
+ case eTypeStringArray:
+ {
+ const size_t argc = m_string_values.GetArgumentCount();
+ result.AppendMessageWithFormat (" %s (string vector):\n", m_name.c_str());
+ for (size_t i = 0; i < argc; ++i)
+ result.AppendMessageWithFormat (" [%d] %s\n", i, m_string_values.GetArgumentAtIndex(i));
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+StateVariable::SetStringValue (const char *new_value)
+{
+ if (m_string_values.GetArgumentCount() > 0)
+ m_string_values.ReplaceArgumentAtIndex(0, new_value);
+ else
+ m_string_values.AppendArgument(new_value);
+}
+
+void
+StateVariable::SetIntValue (int new_value)
+{
+ m_int_value = new_value;
+}
+
+void
+StateVariable::SetBoolValue (bool new_value)
+{
+ m_int_value = new_value;
+}
+
+void
+StateVariable::AppendStringValue (const char *cstr)
+{
+ if (cstr && cstr[0])
+ {
+ if (m_string_values.GetArgumentCount() == 0)
+ {
+ m_string_values.AppendArgument(cstr);
+ }
+ else
+ {
+ const char *curr_arg = m_string_values.GetArgumentAtIndex(0);
+ if (curr_arg != NULL)
+ {
+ std::string new_arg_str(curr_arg);
+ new_arg_str += " ";
+ new_arg_str += cstr;
+ m_string_values.ReplaceArgumentAtIndex(0, new_arg_str.c_str());
+ }
+ else
+ {
+ m_string_values.ReplaceArgumentAtIndex(0, cstr);
+ }
+ }
+ }
+}
+
+bool
+StateVariable::VerifyValue (CommandInterpreter *interpreter, void *data, CommandReturnObject &result)
+{
+ return (*m_verification_func_ptr) (interpreter, data, result);
+}
+
+//void
+//StateVariable::SetArrayValue (STLStringArray &new_value)
+//{
+// m_string_values.AppendArgument.append(cstr);
+//
+// if (m_array_value != NULL)
+// {
+// if (m_array_value->size() > 0)
+// {
+// m_array_value->clear();
+// }
+// }
+// else
+// m_array_value = new STLStringArray;
+//
+// for (int i = 0; i < new_value.size(); ++i)
+// m_array_value->push_back (new_value[i]);
+//}
+//
+
+void
+StateVariable::ArrayClearValues ()
+{
+ m_string_values.Clear();
+}
+
+
+void
+StateVariable::ArrayAppendValue (const char *cstr)
+{
+ m_string_values.AppendArgument(cstr);
+}
+
+
+bool
+StateVariable::HasVerifyFunction ()
+{
+ return (m_verification_func_ptr != NULL);
+}
+
+// Verification functions for various command interpreter variables.
+
+bool
+StateVariable::VerifyScriptLanguage (CommandInterpreter *interpreter, void *data, CommandReturnObject &result)
+{
+ bool valid_lang = true;
+ interpreter->SetScriptLanguage (Args::StringToScriptLanguage((char *) data, eScriptLanguageDefault, &valid_lang));
+ return valid_lang;
+}
+
+bool
+StateVariable::BroadcastPromptChange (CommandInterpreter *interpreter, void *data, CommandReturnObject &result)
+{
+ char *prompt = (char *) data;
+ if (prompt != NULL)
+ {
+ std::string tmp_prompt = prompt ;
+ int len = tmp_prompt.size();
+ if (len > 1
+ && (tmp_prompt[0] == '\'' || tmp_prompt[0] == '"')
+ && (tmp_prompt[len-1] == tmp_prompt[0]))
+ {
+ tmp_prompt = tmp_prompt.substr(1,len-2);
+ }
+ len = tmp_prompt.size();
+ if (tmp_prompt[len-1] != ' ')
+ tmp_prompt.append(" ");
+ strcpy (prompt, tmp_prompt.c_str());
+ data = (void *) prompt;
+ }
+ EventSP new_event_sp;
+ new_event_sp.reset (new Event(CommandInterpreter::eBroadcastBitResetPrompt, new EventDataBytes (prompt)));
+ interpreter->BroadcastEvent (new_event_sp);
+
+ return true;
+}
+
diff --git a/lldb/source/Interpreter/embedded_interpreter.py b/lldb/source/Interpreter/embedded_interpreter.py
new file mode 100644
index 00000000000..38b2f9ef01e
--- /dev/null
+++ b/lldb/source/Interpreter/embedded_interpreter.py
@@ -0,0 +1,90 @@
+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()"):
+ 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 run_python_interpreter (dict):
+ # Pass in the dictionary, for continuity from one session to the next.
+ repl = SimpleREPL('>>> ', dict)
+ repl.interact()
diff --git a/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
new file mode 100644
index 00000000000..09cc09d024c
--- /dev/null
+++ b/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
@@ -0,0 +1,578 @@
+//===-- 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/Scalar.h"
+#include "lldb/Symbol/ClangASTContext.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;
+
+static const char *pluginName = "ABIMacOSX_i386";
+static const char *pluginDesc = "Mac OS X ABI for i386 targets";
+static const char *pluginShort = "abi.macosx-i386";
+
+size_t
+ABIMacOSX_i386::GetRedZoneSize () const
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+lldb_private::ABI *
+ABIMacOSX_i386::CreateInstance (const ConstString &triple)
+{
+ llvm::StringRef tripleStr(triple.GetCString());
+ llvm::Triple llvmTriple(tripleStr);
+
+ if (llvmTriple.getArch() != llvm::Triple::x86)
+ return NULL;
+
+ return new ABIMacOSX_i386;
+}
+
+bool
+ABIMacOSX_i386::PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ lldb::addr_t arg) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+ if (!reg_ctx)
+ return false;
+
+ uint32_t ebpID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ uint32_t eipID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t espID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // Make room for the argument on the stack
+
+ sp -= 4;
+
+ // Align the SP
+
+ sp &= ~(0xfull); // 16-byte alignment
+
+ // Write the argument on the stack
+
+ uint32_t argU32 = arg & 0xffffffffull;
+ Error error;
+ if (thread.GetProcess().WriteMemory (sp, &argU32, sizeof(argU32), error) != sizeof(argU32))
+ return false;
+
+ // The return address is pushed onto the stack.
+
+ sp -= 4;
+ uint32_t returnAddressU32 = returnAddress;
+ if (thread.GetProcess().WriteMemory (sp, &returnAddressU32, sizeof(returnAddressU32), error) != sizeof(returnAddressU32))
+ return false;
+
+ // %esp is set to the actual stack value.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(espID, sp))
+ return false;
+
+ // %ebp is set to a fake value, in our case 0x0x00000000
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(ebpID, 0x00000000))
+ return false;
+
+ // %eip is set to the address of the called function.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(eipID, functionAddress))
+ return false;
+
+ return true;
+}
+
+bool
+ABIMacOSX_i386::PrepareNormalCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ ValueList &args) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+ if (!reg_ctx)
+ return false;
+ Error error;
+ uint32_t ebpID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ uint32_t eipID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t espID = 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:
+ default:
+ 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:
+ switch (val->GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ void *val_type = val->GetOpaqueClangQualType();
+ uint32_t cstr_length;
+
+ if (ClangASTContext::IsCStringType (val_type, 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 (thread.GetProcess().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 &= ~(0xfull); // 16-byte alignment
+
+ // Write the arguments on the stack
+
+ size_t numChunks = argLayout.size();
+
+ for (index = 0; index < numChunks; ++index)
+ if (thread.GetProcess().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 = returnAddress;
+ if (thread.GetProcess().WriteMemory (sp, &returnAddressU32, sizeof(returnAddressU32), error) != sizeof(returnAddressU32))
+ return false;
+
+ // %esp is set to the actual stack value.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(espID, sp))
+ return false;
+
+ // %ebp is set to a fake value, in our case 0x0x00000000
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(ebpID, 0x00000000))
+ return false;
+
+ // %eip is set to the address of the called function.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(eipID, functionAddress))
+ return false;
+
+ return true;
+}
+
+static bool ReadIntegerArgument(Scalar &scalar,
+ unsigned int bit_width,
+ bool is_signed,
+ Process &process,
+ addr_t &current_stack_argument)
+{
+ if (bit_width > 64)
+ return false; // Scalar can't hold large integer arguments
+
+ uint64_t arg_contents;
+ uint32_t read_data;
+ Error error;
+
+ if (bit_width > 32)
+ {
+ if (process.ReadMemory(current_stack_argument, &read_data, sizeof(read_data), error) != sizeof(read_data))
+ return false;
+
+ arg_contents = read_data;
+
+ if (process.ReadMemory(current_stack_argument + 4, &read_data, sizeof(read_data), error) != sizeof(read_data))
+ return false;
+
+ arg_contents |= ((uint64_t)read_data) << 32;
+
+ current_stack_argument += 8;
+ }
+ else {
+ if (process.ReadMemory(current_stack_argument, &read_data, sizeof(read_data), error) != sizeof(read_data))
+ return false;
+
+ arg_contents = read_data;
+
+ current_stack_argument += 4;
+ }
+
+ if (is_signed)
+ {
+ switch (bit_width)
+ {
+ default:
+ return false;
+ case 8:
+ scalar = (int8_t)(arg_contents & 0xff);
+ break;
+ case 16:
+ scalar = (int16_t)(arg_contents & 0xffff);
+ break;
+ case 32:
+ scalar = (int32_t)(arg_contents & 0xffffffff);
+ break;
+ case 64:
+ scalar = (int64_t)arg_contents;
+ break;
+ }
+ }
+ else
+ {
+ switch (bit_width)
+ {
+ default:
+ return false;
+ case 8:
+ scalar = (uint8_t)(arg_contents & 0xff);
+ break;
+ case 16:
+ scalar = (uint16_t)(arg_contents & 0xffff);
+ break;
+ case 32:
+ scalar = (uint32_t)(arg_contents & 0xffffffff);
+ break;
+ case 64:
+ scalar = (uint64_t)arg_contents;
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool
+ABIMacOSX_i386::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ unsigned int num_values = values.GetSize();
+ unsigned int value_index;
+
+ // Extract the Clang AST context from the PC so that we can figure out type
+ // sizes
+
+ clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+
+ 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?
+ switch (value->GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ void *value_type = value->GetOpaqueClangQualType();
+ bool is_signed;
+
+ if (ClangASTContext::IsIntegerType (value_type, is_signed))
+ {
+ size_t bit_width = ClangASTContext::GetTypeBitSize(ast_context, value_type);
+
+ ReadIntegerArgument(value->GetScalar(),
+ bit_width,
+ is_signed,
+ thread.GetProcess(),
+ current_stack_argument);
+ }
+ else if (ClangASTContext::IsPointerType (value_type))
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ 32,
+ false,
+ thread.GetProcess(),
+ current_stack_argument);
+ }
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool
+ABIMacOSX_i386::GetReturnValue (Thread &thread,
+ Value &value) const
+{
+ switch (value.GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ // Extract the Clang AST context from the PC so that we can figure out type
+ // sizes
+
+ clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+
+ void *value_type = value.GetOpaqueClangQualType();
+ bool is_signed;
+
+ if (ClangASTContext::IsIntegerType (value_type, is_signed))
+ {
+ size_t bit_width = ClangASTContext::GetTypeBitSize(ast_context, value_type);
+
+ unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->reg;
+ unsigned edx_id = reg_ctx->GetRegisterInfoByName("edx", 0)->reg;
+
+ switch (bit_width)
+ {
+ default:
+ case 128:
+ // Scalar can't hold 128-bit literals, so we don't handle this
+ return false;
+ 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 (ClangASTContext::IsPointerType (value_type))
+ {
+ unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->reg;
+ uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
+ value.GetScalar() = ptr;
+ }
+ else
+ {
+ // not handled yet
+ return false;
+ }
+ }
+ break;
+ }
+
+ return true;
+}
+
+void
+ABIMacOSX_i386::Initialize()
+{
+ PluginManager::RegisterPlugin (pluginName,
+ pluginDesc,
+ CreateInstance);
+}
+
+void
+ABIMacOSX_i386::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ABIMacOSX_i386::GetPluginName()
+{
+ return pluginName;
+}
+
+const char *
+ABIMacOSX_i386::GetShortPluginName()
+{
+ return pluginShort;
+}
+
+uint32_t
+ABIMacOSX_i386::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ABIMacOSX_i386::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ABIMacOSX_i386::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ABIMacOSX_i386::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
diff --git a/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
new file mode 100644
index 00000000000..c27569b5a14
--- /dev/null
+++ b/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
@@ -0,0 +1,93 @@
+//===-- 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"
+
+namespace lldb_private {
+
+ class ABIMacOSX_i386 :
+ public lldb_private::ABI
+ {
+ public:
+ ~ABIMacOSX_i386() { }
+
+ virtual size_t
+ GetRedZoneSize () const;
+
+ virtual bool
+ PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ lldb::addr_t arg) const;
+
+ virtual bool
+ PrepareNormalCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ ValueList &args) const;
+
+ virtual bool
+ GetArgumentValues (Thread &thread,
+ ValueList &values) const;
+
+ virtual bool
+ GetReturnValue (Thread &thread,
+ Value &value) const;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ABI *
+ CreateInstance (const ConstString &triple);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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:
+ private:
+ ABIMacOSX_i386() : lldb_private::ABI() { } // Call CreateInstance instead.
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_ABI_h_
diff --git a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
new file mode 100644
index 00000000000..004be60c377
--- /dev/null
+++ b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
@@ -0,0 +1,412 @@
+//===-- 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/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Symbol/ClangASTContext.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;
+
+static const char *pluginName = "ABISysV_x86_64";
+static const char *pluginDesc = "System V ABI for x86_64 targets";
+static const char *pluginShort = "abi.sysv-x86_64";
+
+size_t
+ABISysV_x86_64::GetRedZoneSize () const
+{
+ return 128;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+lldb_private::ABI *
+ABISysV_x86_64::CreateInstance (const ConstString &triple)
+{
+ llvm::StringRef tripleStr(triple.GetCString());
+ llvm::Triple llvmTriple(tripleStr);
+
+ if (llvmTriple.getArch() != llvm::Triple::x86_64)
+ return NULL;
+
+ return new ABISysV_x86_64;
+}
+
+bool
+ABISysV_x86_64::PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ lldb::addr_t arg) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+ if (!reg_ctx)
+ return false;
+
+ uint32_t rdiID = reg_ctx->GetRegisterInfoByName("rdi", 0)->reg;
+ uint32_t rbpID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ uint32_t ripID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t rspID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // The argument is in %rdi, and not on the stack.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(rdiID, arg))
+ return false;
+
+ // First, align the SP
+
+ sp &= ~(0xfull); // 16-byte alignment
+
+ // The return address is pushed onto the stack.
+
+ sp -= 8;
+ uint64_t returnAddressU64 = returnAddress;
+ Error error;
+ if (thread.GetProcess().WriteMemory (sp, &returnAddressU64, sizeof(returnAddressU64), error) != sizeof(returnAddressU64))
+ return false;
+
+ // %rsp is set to the actual stack value.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(rspID, sp))
+ return false;
+
+ // %rbp is set to a fake value, in our case 0x0000000000000000.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(rbpID, 0x000000000000000))
+ return false;
+
+ // %rip is set to the address of the called function.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(ripID, functionAddress))
+ return false;
+
+ return true;
+}
+
+bool
+ABISysV_x86_64::PrepareNormalCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ ValueList &args) const
+{
+ return false;
+}
+
+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
+
+ uint64_t arg_contents;
+
+ if (current_argument_register < 6)
+ {
+ arg_contents = thread.GetRegisterContext()->ReadRegisterAsUnsigned(argument_register_ids[current_argument_register], 0);
+ current_argument_register++;
+ }
+ else
+ {
+ uint8_t arg_data[sizeof(arg_contents)];
+ Error error;
+ thread.GetProcess().ReadMemory(current_stack_argument, arg_data, sizeof(arg_contents), error);
+ DataExtractor arg_data_extractor(arg_data, sizeof(arg_contents), thread.GetProcess().GetByteOrder(), thread.GetProcess().GetAddressByteSize());
+ uint32_t offset = 0;
+ arg_contents = arg_data_extractor.GetMaxU64(&offset, bit_width / 8);
+ if (!offset)
+ return false;
+ current_stack_argument += (bit_width / 8);
+ }
+
+ if (is_signed)
+ {
+ switch (bit_width)
+ {
+ default:
+ return false;
+ case 8:
+ scalar = (int8_t)(arg_contents & 0xff);
+ break;
+ case 16:
+ scalar = (int16_t)(arg_contents & 0xffff);
+ break;
+ case 32:
+ scalar = (int32_t)(arg_contents & 0xffffffff);
+ break;
+ case 64:
+ scalar = (int64_t)arg_contents;
+ break;
+ }
+ }
+ else
+ {
+ switch (bit_width)
+ {
+ default:
+ return false;
+ case 8:
+ scalar = (uint8_t)(arg_contents & 0xff);
+ break;
+ case 16:
+ scalar = (uint16_t)(arg_contents & 0xffff);
+ break;
+ case 32:
+ scalar = (uint32_t)(arg_contents & 0xffffffff);
+ break;
+ case 64:
+ scalar = (uint64_t)arg_contents;
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool
+ABISysV_x86_64::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ unsigned int num_values = values.GetSize();
+ unsigned int value_index;
+
+ // For now, assume that the types in the AST values come from the Target's
+ // scratch AST.
+
+ clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
+
+ // Extract the register context so we can read arguments from registers
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+
+ 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)->reg;
+ argument_register_ids[1] = reg_ctx->GetRegisterInfoByName("rsi", 0)->reg;
+ argument_register_ids[2] = reg_ctx->GetRegisterInfoByName("rdx", 0)->reg;
+ argument_register_ids[3] = reg_ctx->GetRegisterInfoByName("rcx", 0)->reg;
+ argument_register_ids[4] = reg_ctx->GetRegisterInfoByName("r8", 0)->reg;
+ argument_register_ids[5] = reg_ctx->GetRegisterInfoByName("r9", 0)->reg;
+
+ 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?
+ switch (value->GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ void *value_type = value->GetOpaqueClangQualType();
+ bool is_signed;
+
+ if (ClangASTContext::IsIntegerType (value_type, is_signed))
+ {
+ size_t bit_width = ClangASTContext::GetTypeBitSize(ast_context, value_type);
+
+ ReadIntegerArgument(value->GetScalar(),
+ bit_width,
+ is_signed,
+ thread,
+ argument_register_ids,
+ current_argument_register,
+ current_stack_argument);
+ }
+ else if (ClangASTContext::IsPointerType (value_type))
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ 64,
+ false,
+ thread,
+ argument_register_ids,
+ current_argument_register,
+ current_stack_argument);
+ }
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool
+ABISysV_x86_64::GetReturnValue (Thread &thread,
+ Value &value) const
+{
+ switch (value.GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ void *value_type = value.GetOpaqueClangQualType();
+ bool is_signed;
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+
+ if (!reg_ctx)
+ return false;
+
+ if (ClangASTContext::IsIntegerType (value_type, is_signed))
+ {
+ // For now, assume that the types in the AST values come from the Target's
+ // scratch AST.
+
+ clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
+
+ // Extract the register context so we can read arguments from registers
+
+ size_t bit_width = ClangASTContext::GetTypeBitSize(ast_context, value_type);
+ unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->reg;
+
+ switch (bit_width)
+ {
+ default:
+ case 128:
+ // Scalar can't hold 128-bit literals, so we don't handle this
+ return false;
+ case 64:
+ if (is_signed)
+ value.GetScalar() = (int64_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0));
+ else
+ value.GetScalar() = (uint64_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0));
+ break;
+ case 32:
+ if (is_signed)
+ value.GetScalar() = (int32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffffffff);
+ else
+ value.GetScalar() = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffffffff);
+ break;
+ case 16:
+ if (is_signed)
+ value.GetScalar() = (int16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffff);
+ else
+ value.GetScalar() = (uint16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xffff);
+ break;
+ case 8:
+ if (is_signed)
+ value.GetScalar() = (int8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xff);
+ else
+ value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0) & 0xff);
+ break;
+ }
+ }
+ else if (ClangASTContext::IsPointerType (value_type))
+ {
+ unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->reg;
+ value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0);
+ }
+ else
+ {
+ // not handled yet
+ return false;
+ }
+ }
+ break;
+ }
+
+ return true;
+}
+
+void
+ABISysV_x86_64::Initialize()
+{
+ PluginManager::RegisterPlugin (pluginName,
+ pluginDesc,
+ CreateInstance);
+}
+
+void
+ABISysV_x86_64::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ABISysV_x86_64::GetPluginName()
+{
+ return pluginName;
+}
+
+const char *
+ABISysV_x86_64::GetShortPluginName()
+{
+ return pluginShort;
+}
+
+uint32_t
+ABISysV_x86_64::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ABISysV_x86_64::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ABISysV_x86_64::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ABISysV_x86_64::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
diff --git a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
new file mode 100644
index 00000000000..b89d7c6581c
--- /dev/null
+++ b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
@@ -0,0 +1,92 @@
+//===-- 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"
+
+namespace lldb_private {
+
+class ABISysV_x86_64 :
+ public lldb_private::ABI
+{
+public:
+ ~ABISysV_x86_64() { }
+
+ virtual size_t
+ GetRedZoneSize () const;
+
+ virtual bool
+ PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ lldb::addr_t arg) const;
+
+ virtual bool
+ PrepareNormalCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ ValueList &args) const;
+
+ virtual bool
+ GetArgumentValues (Thread &thread,
+ ValueList &values) const;
+
+ virtual bool
+ GetReturnValue (Thread &thread,
+ Value &value) const;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ABI *
+ CreateInstance (const ConstString &triple);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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:
+private:
+ ABISysV_x86_64() : lldb_private::ABI() { } // Call CreateInstance instead.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ABI_h_
diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp
new file mode 100644
index 00000000000..db2d561b24a
--- /dev/null
+++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp
@@ -0,0 +1,468 @@
+//===-- DisassemblerLLVM.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DisassemblerLLVM.h"
+
+#include "llvm-c/EnhancedDisassembly.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.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 <memory>
+#include <string>
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static
+int DataExtractorByteReader(uint8_t *byte, uint64_t address, void *arg)
+{
+ DataExtractor &extractor = *((DataExtractor *)arg);
+
+ if (extractor.ValidOffset(address))
+ {
+ *byte = *(extractor.GetDataStart() + address);
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+namespace {
+ struct RegisterReaderArg {
+ const lldb::addr_t instructionPointer;
+ const EDDisassemblerRef disassembler;
+
+ RegisterReaderArg(lldb::addr_t ip,
+ EDDisassemblerRef dis) :
+ instructionPointer(ip),
+ disassembler(dis)
+ {
+ }
+ };
+}
+
+static int IPRegisterReader(uint64_t *value, unsigned regID, void* arg)
+{
+ uint64_t instructionPointer = ((RegisterReaderArg*)arg)->instructionPointer;
+ EDDisassemblerRef disassembler = ((RegisterReaderArg*)arg)->disassembler;
+
+ if(EDRegisterIsProgramCounter(disassembler, regID)) {
+ *value = instructionPointer;
+ return 0;
+ }
+
+ return -1;
+}
+
+DisassemblerLLVM::Instruction::Instruction(EDDisassemblerRef disassembler) :
+ Disassembler::Instruction (),
+ m_disassembler (disassembler)
+{
+}
+
+DisassemblerLLVM::Instruction::~Instruction()
+{
+}
+
+static void
+PadString(Stream *s, const std::string &str, size_t width)
+{
+ int diff = width - str.length();
+
+ if (diff > 0)
+ s->Printf("%s%*.*s", str.c_str(), diff, diff, "");
+ else
+ s->Printf("%s ", str.c_str());
+}
+
+void
+DisassemblerLLVM::Instruction::Dump
+(
+ Stream *s,
+ lldb::addr_t base_address,
+ DataExtractor *bytes,
+ uint32_t bytes_offset,
+ const lldb_private::ExecutionContext exe_ctx,
+ bool raw
+)
+{
+ const size_t opcodeColumnWidth = 7;
+ const size_t operandColumnWidth = 25;
+
+ // If we have an address, print it out
+ if (base_address != LLDB_INVALID_ADDRESS)
+ s->Printf("0x%llx: ", base_address);
+
+ // If we are supposed to show bytes, "bytes" will be non-NULL.
+ if (bytes)
+ {
+ uint32_t bytes_dumped = bytes->Dump(s, bytes_offset, eFormatBytes, 1, EDInstByteSize(m_inst), UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0) - bytes_offset;
+ // Allow for 8 bytes of opcodes normally
+ const uint32_t default_num_opcode_bytes = 9;
+ if (bytes_dumped * 3 < (default_num_opcode_bytes*3))
+ {
+ uint32_t indent_level = (default_num_opcode_bytes*3) - (bytes_dumped * 3);
+ s->Printf("%*.*s", indent_level, indent_level, "");
+ }
+ }
+
+ int numTokens = EDNumTokens(m_inst);
+
+ int currentOpIndex = -1;
+
+ RegisterReaderArg rra(base_address + EDInstByteSize(m_inst), m_disassembler);
+
+ lldb_private::Process *process = exe_ctx.process;
+
+ bool printTokenized = false;
+
+ if (numTokens != -1)
+ {
+ printTokenized = true;
+
+ // Handle the opcode column.
+
+ StreamString opcode;
+
+ int tokenIndex = 0;
+
+ EDTokenRef token;
+ const char *tokenStr;
+
+ if (EDGetToken(&token, m_inst, tokenIndex))
+ printTokenized = false;
+
+ if (!printTokenized || !EDTokenIsOpcode(token))
+ printTokenized = false;
+
+ if (!printTokenized || EDGetTokenString(&tokenStr, token))
+ printTokenized = false;
+
+ // Put the token string into our opcode string
+ opcode.PutCString(tokenStr);
+
+ // If anything follows, it probably starts with some whitespace. Skip it.
+
+ tokenIndex++;
+
+ if (printTokenized && tokenIndex < numTokens)
+ {
+ if(!printTokenized || EDGetToken(&token, m_inst, tokenIndex))
+ printTokenized = false;
+
+ if(!printTokenized || !EDTokenIsWhitespace(token))
+ printTokenized = false;
+ }
+
+ tokenIndex++;
+
+ // Handle the operands and the comment.
+
+ StreamString operands;
+ StreamString comment;
+
+ if (printTokenized)
+ {
+ bool show_token;
+
+ for (; tokenIndex < numTokens; ++tokenIndex)
+ {
+ if (EDGetToken(&token, m_inst, tokenIndex))
+ return;
+
+ if (raw)
+ {
+ show_token = true;
+ }
+ else
+ {
+ int operandIndex = EDOperandIndexForToken(token);
+
+ if (operandIndex >= 0)
+ {
+ if (operandIndex != currentOpIndex)
+ {
+ show_token = true;
+
+ currentOpIndex = operandIndex;
+ EDOperandRef operand;
+
+ if (!EDGetOperand(&operand, m_inst, currentOpIndex))
+ {
+ if (EDOperandIsMemory(operand))
+ {
+ uint64_t operand_value;
+
+ if (!EDEvaluateOperand(&operand_value, operand, IPRegisterReader, &rra))
+ {
+ if (EDInstIsBranch(m_inst))
+ {
+ operands.Printf("0x%llx ", operand_value);
+ show_token = false;
+ }
+ else
+ {
+ // Put the address value into the comment
+ comment.Printf("0x%llx ", operand_value);
+ }
+
+ lldb_private::Address so_addr;
+ if (process)
+ {
+ if (process->ResolveLoadAddress(operand_value, so_addr))
+ {
+ so_addr.Dump(&comment, process, Address::DumpStyleResolvedDescription, Address::DumpStyleSectionNameOffset);
+ }
+ }
+ } // EDEvaluateOperand
+ } // EDOperandIsMemory
+ } // EDGetOperand
+ } // operandIndex != currentOpIndex
+ } // operandIndex >= 0
+ } // else(raw)
+
+ if (show_token)
+ {
+ if(EDGetTokenString(&tokenStr, token))
+ {
+ printTokenized = false;
+ break;
+ }
+
+ operands.PutCString(tokenStr);
+ }
+ } // for (tokenIndex)
+
+ if (printTokenized)
+ {
+ if (operands.GetString().empty())
+ {
+ s->PutCString(opcode.GetString().c_str());
+ }
+ else
+ {
+ PadString(s, opcode.GetString(), opcodeColumnWidth);
+
+ if (comment.GetString().empty())
+ {
+ s->PutCString(operands.GetString().c_str());
+ }
+ else
+ {
+ PadString(s, operands.GetString(), operandColumnWidth);
+
+ s->PutCString("; ");
+ s->PutCString(comment.GetString().c_str());
+ } // else (comment.GetString().empty())
+ } // else (operands.GetString().empty())
+ } // printTokenized
+ } // for (tokenIndex)
+ } // numTokens != -1
+
+ if (!printTokenized)
+ {
+ const char *str;
+
+ if (EDGetInstString(&str, m_inst))
+ return;
+ else
+ s->PutCString(str);
+ }
+}
+
+bool
+DisassemblerLLVM::Instruction::DoesBranch() const
+{
+ return EDInstIsBranch(m_inst);
+}
+
+size_t
+DisassemblerLLVM::Instruction::GetByteSize() const
+{
+ return EDInstByteSize(m_inst);
+}
+
+size_t
+DisassemblerLLVM::Instruction::Extract(const DataExtractor &data, uint32_t data_offset)
+{
+ if (EDCreateInsts(&m_inst, 1, m_disassembler, DataExtractorByteReader, data_offset, (void*)(&data)))
+ return EDInstByteSize(m_inst);
+ else
+ return 0;
+}
+
+static inline const char *
+TripleForCPU(cpu_type_t cpuType)
+{
+ switch (cpuType)
+ {
+ default:
+ return NULL;
+ case CPU_TYPE_X86:
+ return "i386-unknown-unknown";
+ case CPU_TYPE_X86_64:
+ return "x86_64-unknown-unknown";
+ }
+}
+
+static inline EDAssemblySyntax_t
+SyntaxForCPU(cpu_type_t cpuType)
+{
+ switch (cpuType)
+ {
+ default:
+ return (EDAssemblySyntax_t)0; // default
+ case CPU_TYPE_X86:
+ case CPU_TYPE_X86_64:
+ return kEDAssemblySyntaxX86ATT;
+ }
+}
+
+Disassembler *
+DisassemblerLLVM::CreateInstance(const ArchSpec &arch)
+{
+ cpu_type_t cpuType = arch.GetCPUType();
+
+ if (TripleForCPU(cpuType))
+ return new DisassemblerLLVM(arch);
+ else
+ return NULL;
+}
+
+DisassemblerLLVM::DisassemblerLLVM(const ArchSpec &arch) :
+ Disassembler(arch)
+{
+ cpu_type_t cpuType = arch.GetCPUType();
+
+ const char *triple = TripleForCPU(cpuType);
+ assert(triple && "Unhandled CPU type!");
+
+ EDAssemblySyntax_t syntax = SyntaxForCPU(cpuType);
+
+ assert(!EDGetDisassembler(&m_disassembler, triple, syntax) && "No disassembler created!");
+}
+
+DisassemblerLLVM::~DisassemblerLLVM()
+{
+}
+
+size_t
+DisassemblerLLVM::ParseInstructions
+(
+ const DataExtractor& data,
+ uint32_t data_offset,
+ uint32_t num_instructions,
+ lldb::addr_t base_addr
+)
+{
+ size_t total_inst_byte_size = 0;
+
+ m_instruction_list.Clear();
+
+ while (data.ValidOffset(data_offset) && num_instructions)
+ {
+ Instruction::shared_ptr inst_sp (new Instruction(m_disassembler));
+
+ size_t inst_byte_size = inst_sp->Extract(data, data_offset);
+
+ if (inst_byte_size == 0)
+ break;
+
+ m_instruction_list.AppendInstruction(inst_sp);
+
+ total_inst_byte_size += inst_byte_size;
+ data_offset += inst_byte_size;
+ num_instructions--;
+ }
+
+ return total_inst_byte_size;
+}
+
+void
+DisassemblerLLVM::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DisassemblerLLVM::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+DisassemblerLLVM::GetPluginNameStatic()
+{
+ return "disassembler.llvm";
+}
+
+const char *
+DisassemblerLLVM::GetPluginDescriptionStatic()
+{
+ return "Disassembler that uses LLVM opcode tables to disassemble i386 and x86_64.";
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+DisassemblerLLVM::GetPluginName()
+{
+ return "DisassemblerLLVM";
+}
+
+const char *
+DisassemblerLLVM::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+DisassemblerLLVM::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+DisassemblerLLVM::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+DisassemblerLLVM::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+DisassemblerLLVM::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.h b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.h
new file mode 100644
index 00000000000..98166cb558c
--- /dev/null
+++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.h
@@ -0,0 +1,111 @@
+//===-- DisassemblerLLVM.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_DisassemblerLLVM_h_
+#define liblldb_DisassemblerLLVM_h_
+
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Host/Mutex.h"
+
+struct EDDisassembler;
+typedef EDDisassembler *EDDisassemblerRef;
+
+struct EDInst;
+typedef EDInst *EDInstRef;
+
+class DisassemblerLLVM : public lldb_private::Disassembler
+{
+public:
+ class Instruction : public lldb_private::Disassembler::Instruction
+ {
+ public:
+ Instruction(EDDisassemblerRef disassembler);
+
+ virtual
+ ~Instruction();
+
+ void
+ Dump (lldb_private::Stream *s,
+ lldb::addr_t base_address,
+ lldb_private::DataExtractor *bytes,
+ uint32_t bytes_offset,
+ const lldb_private::ExecutionContext exe_ctx,
+ bool raw);
+
+ bool
+ DoesBranch () const;
+
+ size_t
+ GetByteSize() const;
+
+ size_t
+ Extract (const lldb_private::DataExtractor &data,
+ uint32_t data_offset);
+
+ protected:
+ EDDisassemblerRef m_disassembler;
+ EDInstRef m_inst;
+ };
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::Disassembler *
+ CreateInstance(const lldb_private::ArchSpec &arch);
+
+
+ DisassemblerLLVM(const lldb_private::ArchSpec &arch);
+
+ virtual
+ ~DisassemblerLLVM();
+
+ size_t
+ ParseInstructions (const lldb_private::DataExtractor& data,
+ uint32_t data_offset,
+ uint32_t num_instructions,
+ lldb::addr_t base_addr);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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:
+ EDDisassemblerRef m_disassembler;
+};
+
+#endif // liblldb_DisassemblerLLVM_h_
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp
new file mode 100644
index 00000000000..a8dbf053e3d
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp
@@ -0,0 +1,1129 @@
+//===-- DynamicLoaderMacOSXDYLD.cpp -----------------------------*- 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"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Target/StackFrame.h"
+
+#include "DynamicLoaderMacOSXDYLD.h"
+#include "DynamicLoaderMacOSXDYLDLog.h"
+
+//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
+#ifdef ENABLE_DEBUG_PRINTF
+#include <stdio.h>
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+/// FIXME - The ObjC Runtime trampoline handler doesn't really belong here.
+/// I am putting it here so I can invoke it in the Trampoline code here, but
+/// it should be moved to the ObjC Runtime support when it is set up.
+
+//----------------------------------------------------------------------
+// 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 *
+DynamicLoaderMacOSXDYLD::CreateInstance (Process* process)
+{
+ return new DynamicLoaderMacOSXDYLD (process);
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DynamicLoaderMacOSXDYLD::DynamicLoaderMacOSXDYLD (Process* process) :
+ DynamicLoader(process),
+ m_dyld(),
+ m_dyld_all_image_infos_addr(LLDB_INVALID_ADDRESS),
+ m_dyld_all_image_infos(),
+ m_break_id(LLDB_INVALID_BREAK_ID),
+ m_dyld_image_infos(),
+ m_mutex(Mutex::eMutexTypeRecursive),
+ m_objc_trampoline_handler_ap(NULL)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DynamicLoaderMacOSXDYLD::~DynamicLoaderMacOSXDYLD()
+{
+ Clear(true);
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::DidAttach ()
+{
+ PrivateInitialize(m_process);
+ if (NeedToLocateDYLD ())
+ LocateDYLD ();
+ SetNotificationBreakpoint ();
+ UpdateAllImageInfos();
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::DidLaunch ()
+{
+ PrivateInitialize(m_process);
+ if (NeedToLocateDYLD ())
+ LocateDYLD ();
+ SetNotificationBreakpoint ();
+ UpdateAllImageInfos();
+}
+
+
+//----------------------------------------------------------------------
+// Clear out the state of this class.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::Clear (bool clear_process)
+{
+ Mutex::Locker locker(m_mutex);
+
+ if (m_process->IsAlive() && LLDB_BREAK_ID_IS_VALID(m_break_id))
+ m_process->ClearBreakpointSiteByID(m_break_id);
+
+ if (clear_process)
+ m_process = NULL;
+ m_dyld.Clear(false);
+ m_dyld_all_image_infos_addr = LLDB_INVALID_ADDRESS;
+ m_dyld_all_image_infos.Clear();
+ m_break_id = LLDB_INVALID_BREAK_ID;
+ m_dyld_image_infos.clear();
+}
+
+//----------------------------------------------------------------------
+// Check if we have found DYLD yet
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::DidSetNotificationBreakpoint() const
+{
+ return LLDB_BREAK_ID_IS_VALID (m_break_id);
+}
+
+//----------------------------------------------------------------------
+// Try and figure out where dyld is by first asking the Process
+// if it knows (which currently calls down in the the lldb::Process
+// to get the DYLD info (available on SnowLeopard only). If that fails,
+// then check in the default addresses.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::LocateDYLD()
+{
+ if (m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS)
+ m_dyld_all_image_infos_addr = m_process->GetImageInfoAddress ();
+
+ if (m_dyld_all_image_infos_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (ReadAllImageInfosStructure ())
+ {
+ if (m_dyld_all_image_infos.dyldImageLoadAddress != LLDB_INVALID_ADDRESS)
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback (m_dyld_all_image_infos.dyldImageLoadAddress);
+ else
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback (m_dyld_all_image_infos_addr & 0xfffffffffff00000ull);
+ }
+ }
+
+ // Check some default values
+ Module *executable = m_process->GetTarget().GetExecutableModule().get();
+
+ if (executable)
+ {
+ if (executable->GetArchitecture().GetAddressByteSize() == 8)
+ {
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x7fff5fc00000ull);
+ }
+#if defined (__arm__)
+ else
+ {
+ ArchSpec arm_arch("arm");
+ if (arm_arch == executable->Arch())
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x2fe00000);
+ }
+#endif
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x8fe00000);
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Assume that dyld is in memory at ADDR and try to parse it's load
+// commands
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::ReadDYLDInfoFromMemoryAndSetNotificationCallback(lldb::addr_t addr)
+{
+ DataExtractor data; // Load command data
+ if (ReadMachHeader (addr, &m_dyld.header, &data))
+ {
+ if (m_dyld.header.filetype == MH_DYLINKER)
+ {
+ m_dyld.address = addr;
+ ModuleSP dyld_module_sp;
+ if (ParseLoadCommands (data, m_dyld, &m_dyld.file_spec))
+ {
+ if (m_dyld.file_spec)
+ {
+ ArchSpec dyld_arch(m_dyld.header.cputype, m_dyld.header.cpusubtype);
+ dyld_module_sp = m_process->GetTarget().GetImages().FindFirstModuleForFileSpec (m_dyld.file_spec);
+
+ if (dyld_module_sp.get() == NULL || dyld_module_sp->GetArchitecture() != dyld_arch)
+ {
+ dyld_module_sp = m_process->GetTarget().GetSharedModule (m_dyld.file_spec,
+ dyld_arch,
+ &m_dyld.uuid);
+ }
+
+ UpdateImageLoadAddress(dyld_module_sp.get(), m_dyld);
+ }
+ }
+
+ if (m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS && dyld_module_sp.get())
+ {
+ static ConstString g_dyld_all_image_infos ("dyld_all_image_infos");
+ const Symbol *symbol = dyld_module_sp->FindFirstSymbolWithNameAndType (g_dyld_all_image_infos, eSymbolTypeData);
+ if (symbol)
+ m_dyld_all_image_infos_addr = symbol->GetValue().GetLoadAddress(m_process);
+ }
+
+ // Update all image infos
+ UpdateAllImageInfos();
+
+ // If we didn't have an executable before, but now we do, then the
+ // dyld module shared pointer might be unique and we may need to add
+ // it again (since Target::SetExecutableModule() will clear the
+ // images). So append the dyld module back to the list if it is
+ /// unique!
+ if (m_process->GetTarget().GetImages().AppendInNeeded (dyld_module_sp))
+ UpdateImageLoadAddress(dyld_module_sp.get(), m_dyld);
+
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+DynamicLoaderMacOSXDYLD::NeedToLocateDYLD () const
+{
+ return m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS;
+}
+
+bool
+DynamicLoaderMacOSXDYLD::UpdateCommPageLoadAddress(Module *module)
+{
+ bool changed = false;
+ if (module)
+ {
+ ObjectFile *image_object_file = module->GetObjectFile();
+ if (image_object_file)
+ {
+ SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ uint32_t num_sections = section_list->GetSize();
+ for (uint32_t i=0; i<num_sections; ++i)
+ {
+ Section* section = section_list->GetSectionAtIndex (i).get();
+ if (section)
+ {
+ const addr_t new_section_load_addr = section->GetFileAddress ();
+ const addr_t old_section_load_addr = m_process->GetSectionLoadAddress (section);
+ if (old_section_load_addr == LLDB_INVALID_ADDRESS ||
+ old_section_load_addr != new_section_load_addr)
+ {
+ if (m_process->SectionLoaded (section, section->GetFileAddress ()))
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+//----------------------------------------------------------------------
+// Update the load addresses for all segments in MODULE using the
+// updated INFO that is passed in.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::UpdateImageLoadAddress (Module *module, struct DYLDImageInfo& info)
+{
+ bool changed = false;
+ if (module)
+ {
+ ObjectFile *image_object_file = module->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)
+ info.slide = 0;
+ 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...
+ Section *section = section_list->GetSectionAtIndex (sect_idx).get();
+ if (section)
+ {
+ // Find the first section that begins at file offset zero
+ // a file size (skip page zero).
+ if (section->GetFileOffset() == 0 && section->GetFileSize() > 0)
+ {
+ // We have now found the section, lets match it up
+ // with the section in the dyld image info structure.
+ const Segment *dyld_segment = info.FindSegment (section->GetName());
+ if (dyld_segment)
+ info.slide = info.address - dyld_segment->addr;
+ // We have found the slide amount, so we can exit
+ // this for loop.
+ break;
+ }
+ }
+ }
+
+ // We now know the slide amount, so go through all sections
+ // and update the load addresses with the correct values.
+ uint32_t num_segments = info.segments.size();
+ for (uint32_t i=0; i<num_segments; ++i)
+ {
+ SectionSP section_sp(section_list->FindSectionByName(info.segments[i].name));
+ assert (section_sp.get() != NULL);
+ const addr_t new_section_load_addr = info.segments[i].addr + info.slide;
+ const addr_t old_section_load_addr = m_process->GetSectionLoadAddress (section_sp.get());
+ if (old_section_load_addr == LLDB_INVALID_ADDRESS ||
+ old_section_load_addr != new_section_load_addr)
+ {
+ if (m_process->SectionLoaded (section_sp.get(), new_section_load_addr))
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+//----------------------------------------------------------------------
+// Update the load addresses for all segments in MODULE using the
+// updated INFO that is passed in.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::UnloadImageLoadAddress (Module *module, struct DYLDImageInfo& info)
+{
+ bool changed = false;
+ if (module)
+ {
+ ObjectFile *image_object_file = module->GetObjectFile();
+ if (image_object_file)
+ {
+ SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ uint32_t num_segments = info.segments.size();
+ for (uint32_t i=0; i<num_segments; ++i)
+ {
+ SectionSP section_sp(section_list->FindSectionByName(info.segments[i].name));
+ assert (section_sp.get() != NULL);
+ const addr_t old_section_load_addr = info.segments[i].addr + info.slide;
+ if (m_process->SectionUnloaded (section_sp.get(), old_section_load_addr))
+ changed = true;
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+
+//----------------------------------------------------------------------
+// Static callback function that gets called when our DYLD notification
+// breakpoint gets hit. We update all of our image infos and then
+// let our super class DynamicLoader class decide if we should stop
+// or not (based on global preference).
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::NotifyBreakpointHit (void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id)
+{
+ // Let the event know that the images have changed
+ DynamicLoaderMacOSXDYLD* dyld_instance = (DynamicLoaderMacOSXDYLD*) baton;
+ dyld_instance->UpdateAllImageInfos();
+ // Return true to stop the target, false to just let the target run
+ return dyld_instance->GetStopWhenImagesChange();
+}
+
+bool
+DynamicLoaderMacOSXDYLD::ReadAllImageInfosStructure ()
+{
+ Mutex::Locker locker(m_mutex);
+ m_dyld_all_image_infos.Clear();
+ if (m_dyld_all_image_infos_addr != LLDB_INVALID_ADDRESS)
+ {
+ const ByteOrder endian = m_process->GetByteOrder();
+ const uint32_t addr_size = m_process->GetAddressByteSize();
+ uint8_t buf[256];
+ const size_t count = 2 * sizeof(uint32_t) + // version + dylib_info_count
+ addr_size * 2 + // dylib_info_addr + notification
+ 2 + addr_size - 2 + // processDetachedFromSharedRegion + libSystemInitialized + pad
+ addr_size; // dyldImageLoadAddress
+ Error error;
+ const size_t bytes_read = m_process->ReadMemory (m_dyld_all_image_infos_addr, buf, count, error);
+ if (bytes_read == count)
+ {
+ DataExtractor data(buf, count, endian, addr_size);
+ uint32_t offset = 0;
+ m_dyld_all_image_infos.version = data.GetU32(&offset);
+ m_dyld_all_image_infos.dylib_info_count = data.GetU32(&offset);
+ m_dyld_all_image_infos.dylib_info_addr = data.GetPointer(&offset);
+ m_dyld_all_image_infos.notification = data.GetPointer(&offset);
+ m_dyld_all_image_infos.processDetachedFromSharedRegion = data.GetU8(&offset);
+ if (m_dyld_all_image_infos.version >= 2)
+ {
+ m_dyld_all_image_infos.libSystemInitialized = data.GetU8(&offset);
+ // Adjust for padding.
+ offset += addr_size - 2;
+ m_dyld_all_image_infos.dyldImageLoadAddress = data.GetPointer(&offset);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// If we have found where the "_dyld_all_image_infos" lives in memory,
+// read the current info from it, and then update all image load
+// addresses (or lack thereof).
+//----------------------------------------------------------------------
+uint32_t
+DynamicLoaderMacOSXDYLD::UpdateAllImageInfos()
+{
+ if (ReadAllImageInfosStructure ())
+ {
+ Mutex::Locker locker(m_mutex);
+ uint32_t idx;
+ Error error;
+ uint32_t i = 0;
+ DYLDImageInfo::collection old_dyld_all_image_infos;
+ old_dyld_all_image_infos.swap(m_dyld_image_infos);
+
+ // If we made it here, we are assuming that the all dylib info data should
+ // be valid, lets read the info array.
+ const ByteOrder endian = m_process->GetByteOrder();
+ const uint32_t addr_size = m_process->GetAddressByteSize();
+
+ if (m_dyld_all_image_infos.dylib_info_count > 0)
+ {
+ if (m_dyld_all_image_infos.dylib_info_addr == 0)
+ {
+ // DYLD is updating the images right now...
+ }
+ else
+ {
+ m_dyld_image_infos.resize(m_dyld_all_image_infos.dylib_info_count);
+ const size_t count = m_dyld_image_infos.size() * 3 * addr_size;
+ DataBufferHeap info_data(count, 0);
+ Error error;
+ const size_t bytes_read = m_process->ReadMemory (m_dyld_all_image_infos.dylib_info_addr,
+ info_data.GetBytes(),
+ info_data.GetByteSize(),
+ error);
+ if (bytes_read == count)
+ {
+ uint32_t info_data_offset = 0;
+ DataExtractor info_data_ref(info_data.GetBytes(), info_data.GetByteSize(), endian, addr_size);
+ for (i = 0; info_data_ref.ValidOffset(info_data_offset); i++)
+ {
+ assert (i < m_dyld_image_infos.size());
+ m_dyld_image_infos[i].address = info_data_ref.GetPointer(&info_data_offset);
+ lldb::addr_t path_addr = info_data_ref.GetPointer(&info_data_offset);
+ m_dyld_image_infos[i].mod_date = info_data_ref.GetPointer(&info_data_offset);
+
+ char raw_path[PATH_MAX];
+ m_process->ReadMemory (path_addr, raw_path, sizeof(raw_path), error);
+ m_dyld_image_infos[i].file_spec.SetFile(raw_path);
+ }
+ assert(i == m_dyld_all_image_infos.dylib_info_count);
+
+ UpdateAllImageInfosHeaderAndLoadCommands();
+ }
+ else
+ {
+ DEBUG_PRINTF( "unable to read all data for all_dylib_infos.");
+ m_dyld_image_infos.clear();
+ }
+ }
+ }
+ else
+ {
+ m_dyld_image_infos.clear();
+ }
+
+ // If our new list is smaller than our old list, we have unloaded
+ // some shared libraries
+ if (m_dyld_image_infos.size() < old_dyld_all_image_infos.size())
+ {
+ ModuleList unloaded_module_list;
+ for (idx = m_dyld_image_infos.size(); idx < old_dyld_all_image_infos.size(); ++idx)
+ {
+ ModuleSP unload_image_module_sp(m_process->GetTarget().GetImages().FindFirstModuleForFileSpec (old_dyld_all_image_infos[idx].file_spec));
+ if (unload_image_module_sp.get())
+ {
+ if (UnloadImageLoadAddress (unload_image_module_sp.get(), old_dyld_all_image_infos[idx]))
+ unloaded_module_list.AppendInNeeded (unload_image_module_sp);
+ }
+ }
+ if (unloaded_module_list.GetSize() > 0)
+ m_process->GetTarget().ModulesDidUnload (unloaded_module_list);
+ }
+ }
+ else
+ {
+ m_dyld_image_infos.clear();
+ }
+
+ const uint32_t num_dylibs = m_dyld_image_infos.size();
+ if (num_dylibs > 0)
+ {
+ ModuleList loaded_module_list;
+ for (uint32_t idx = 0; idx<num_dylibs; ++idx)
+ {
+ ArchSpec arch_spec(m_dyld_image_infos[idx].header.cputype, m_dyld_image_infos[idx].header.cpusubtype);
+ ModuleSP image_module_sp(m_process->GetTarget().GetImages().FindFirstModuleForFileSpec (m_dyld_image_infos[idx].file_spec));
+ if (image_module_sp.get() == NULL || image_module_sp->GetArchitecture() != arch_spec)
+ {
+ image_module_sp = m_process->GetTarget().GetSharedModule (m_dyld_image_infos[idx].file_spec,
+ arch_spec,
+ &m_dyld_image_infos[idx].uuid);
+ }
+
+ if (image_module_sp)
+ {
+ ObjectFile *objfile = image_module_sp->GetObjectFile ();
+ if (objfile)
+ {
+ SectionList *sections = objfile->GetSectionList();
+ if (sections)
+ {
+ ConstString commpage_dbstr("__commpage");
+ Section *commpage_section = sections->FindSectionByName(commpage_dbstr).get();
+ if (commpage_section)
+ {
+ FileSpec objfile_file_spec(objfile->GetFileSpec());
+ ModuleSP commpage_image_module_sp(m_process->GetTarget().GetImages().FindFirstModuleForFileSpec (objfile_file_spec, &commpage_dbstr));
+ if (commpage_image_module_sp.get() == NULL)
+ {
+ commpage_image_module_sp = m_process->GetTarget().GetSharedModule (m_dyld_image_infos[idx].file_spec,
+ arch_spec,
+ &m_dyld_image_infos[idx].uuid,
+ &commpage_dbstr,
+ objfile->GetOffset() + commpage_section->GetOffset());
+ UpdateCommPageLoadAddress(commpage_image_module_sp.get());
+ }
+ }
+ }
+ }
+
+ // UpdateImageLoadAddress will return true if any segments
+ // change load address. We need to check this so we don't
+ // mention that all loaded shared libraries are newly loaded
+ // each time we hit out dyld breakpoint since dyld will list all
+ // shared libraries each time.
+ if (UpdateImageLoadAddress (image_module_sp.get(), m_dyld_image_infos[idx]))
+ {
+ loaded_module_list.AppendInNeeded (image_module_sp);
+ }
+ }
+ }
+ PutToLog(DynamicLoaderMacOSXDYLDLog::GetLogIfAllCategoriesSet (1));
+ if (loaded_module_list.GetSize() > 0)
+ {
+ // FIXME: This should really be in the Runtime handlers class, which should get
+ // called by the target's ModulesDidLoad, but we're doing it all locally for now
+ // to save time.
+ // Also, I'm assuming there can be only one libobjc dylib loaded...
+
+ if (m_objc_trampoline_handler_ap.get() == NULL)
+ {
+ size_t num_modules = loaded_module_list.GetSize();
+ for (int i = 0; i < num_modules; i++)
+ {
+ if (ObjCTrampolineHandler::ModuleIsObjCLibrary (loaded_module_list.GetModuleAtIndex (i)))
+ {
+ m_objc_trampoline_handler_ap.reset (new ObjCTrampolineHandler(m_process->GetSP(), loaded_module_list.GetModuleAtIndex (i)));
+ break;
+ }
+ }
+ }
+ m_process->GetTarget().ModulesDidLoad (loaded_module_list);
+ }
+ }
+ return m_dyld_image_infos.size();
+}
+
+//----------------------------------------------------------------------
+// Read a mach_header at ADDR into HEADER, and also fill in the load
+// command data into LOAD_COMMAND_DATA if it is non-NULL.
+//
+// Returns true if we succeed, false if we fail for any reason.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::ReadMachHeader (lldb::addr_t addr, struct mach_header *header, DataExtractor *load_command_data)
+{
+ DataBufferHeap header_bytes(sizeof(struct mach_header), 0);
+ Error error;
+ size_t bytes_read = m_process->ReadMemory (addr,
+ header_bytes.GetBytes(),
+ header_bytes.GetByteSize(),
+ error);
+ if (bytes_read == sizeof(struct mach_header))
+ {
+ uint32_t offset = 0;
+ ::memset (header, 0, sizeof(header));
+
+ // Get the magic byte unswapped so we can figure out what we are dealing with
+ DataExtractor data(header_bytes.GetBytes(), header_bytes.GetByteSize(), eByteOrderHost, 4);
+ header->magic = data.GetU32(&offset);
+ lldb::addr_t load_cmd_addr = addr;
+ data.SetByteOrder(DynamicLoaderMacOSXDYLD::GetByteOrderFromMagic(header->magic));
+ switch (header->magic)
+ {
+ case MH_MAGIC:
+ case MH_CIGAM:
+ data.SetAddressByteSize(4);
+ load_cmd_addr += sizeof(struct mach_header);
+ break;
+
+ case MH_MAGIC_64:
+ case MH_CIGAM_64:
+ data.SetAddressByteSize(8);
+ load_cmd_addr += sizeof(struct mach_header_64);
+ break;
+
+ default:
+ return false;
+ }
+
+ // Read the rest of dyld's mach header
+ if (data.GetU32(&offset, &header->cputype, (sizeof(struct mach_header)/sizeof(uint32_t)) - 1))
+ {
+ if (load_command_data == NULL)
+ return true; // We were able to read the mach_header and weren't asked to read the load command bytes
+
+ DataBufferSP load_cmd_data_sp(new DataBufferHeap(header->sizeofcmds, 0));
+
+ size_t load_cmd_bytes_read = m_process->ReadMemory (load_cmd_addr,
+ load_cmd_data_sp->GetBytes(),
+ load_cmd_data_sp->GetByteSize(),
+ error);
+
+ if (load_cmd_bytes_read == header->sizeofcmds)
+ {
+ // Set the load command data and also set the correct endian
+ // swap settings and the correct address size
+ load_command_data->SetData(load_cmd_data_sp, 0, header->sizeofcmds);
+ load_command_data->SetByteOrder(data.GetByteOrder());
+ load_command_data->SetAddressByteSize(data.GetAddressByteSize());
+ return true; // We successfully read the mach_header and the load command data
+ }
+
+ return false; // We weren't able to read the load command data
+ }
+ }
+ return false; // We failed the read the mach_header
+}
+
+
+//----------------------------------------------------------------------
+// Parse the load commands for an image
+//----------------------------------------------------------------------
+uint32_t
+DynamicLoaderMacOSXDYLD::ParseLoadCommands (const DataExtractor& data, struct DYLDImageInfo& dylib_info, FileSpec *lc_id_dylinker)
+{
+ uint32_t offset = 0;
+ uint32_t cmd_idx;
+ Segment segment;
+ dylib_info.Clear (true);
+
+ for (cmd_idx = 0; cmd_idx < dylib_info.header.ncmds; cmd_idx++)
+ {
+ // Clear out any load command specific data from DYLIB_INFO since
+ // we are about to read it.
+
+ if (data.ValidOffsetForDataOfSize (offset, sizeof(struct load_command)))
+ {
+ struct load_command load_cmd;
+ uint32_t load_cmd_offset = offset;
+ load_cmd.cmd = data.GetU32 (&offset);
+ load_cmd.cmdsize = data.GetU32 (&offset);
+ switch (load_cmd.cmd)
+ {
+ case LC_SEGMENT:
+ {
+ segment.name.SetTrimmedCStringWithLength ((const char *)data.GetData(&offset, 16), 16);
+ segment.addr = data.GetU32 (&offset);
+ segment.size = data.GetU32 (&offset);
+ dylib_info.segments.push_back (segment);
+ }
+ break;
+
+ case LC_SEGMENT_64:
+ {
+ segment.name.SetTrimmedCStringWithLength ((const char *)data.GetData(&offset, 16), 16);
+ segment.addr = data.GetU64 (&offset);
+ segment.size = data.GetU64 (&offset);
+ dylib_info.segments.push_back (segment);
+ }
+ break;
+
+ case LC_ID_DYLINKER:
+ if (lc_id_dylinker)
+ {
+ uint32_t name_offset = load_cmd_offset + data.GetU32 (&offset);
+ const char *path = data.PeekCStr (name_offset);
+ lc_id_dylinker->SetFile (path);
+ }
+ break;
+
+ case LC_UUID:
+ dylib_info.uuid.SetBytes(data.GetData (&offset, 16));
+ break;
+
+ default:
+ break;
+ }
+ // Set offset to be the beginning of the next load command.
+ offset = load_cmd_offset + load_cmd.cmdsize;
+ }
+ }
+ return cmd_idx;
+}
+
+//----------------------------------------------------------------------
+// Read the mach_header and load commands for each image that the
+// _dyld_all_image_infos structure points to and cache the results.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::UpdateAllImageInfosHeaderAndLoadCommands()
+{
+ uint32_t exe_idx = UINT32_MAX;
+ // Read any UUID values that we can get
+ for (uint32_t i = 0; i < m_dyld_all_image_infos.dylib_info_count; i++)
+ {
+ if (!m_dyld_image_infos[i].UUIDValid())
+ {
+ DataExtractor data; // Load command data
+ if (!ReadMachHeader (m_dyld_image_infos[i].address, &m_dyld_image_infos[i].header, &data))
+ continue;
+
+ ParseLoadCommands (data, m_dyld_image_infos[i], NULL);
+
+ if (m_dyld_image_infos[i].header.filetype == MH_EXECUTE)
+ exe_idx = i;
+ }
+ }
+
+ if (exe_idx < m_dyld_image_infos.size())
+ {
+ bool set_executable = false;
+ ArchSpec dyld_exe_arch_spec(m_dyld_image_infos[exe_idx].header.cputype, m_dyld_image_infos[exe_idx].header.cpusubtype);
+ ModuleSP exe_module_sp(m_process->GetTarget().GetExecutableModule());
+ if (exe_module_sp.get())
+ {
+ if (exe_module_sp->GetFileSpec() != m_dyld_image_infos[exe_idx].file_spec ||
+ exe_module_sp->GetArchitecture() != dyld_exe_arch_spec)
+ set_executable = true;
+ }
+ else
+ set_executable = true;
+
+ if (set_executable)
+ {
+ exe_module_sp = m_process->GetTarget().GetSharedModule (m_dyld_image_infos[exe_idx].file_spec,
+ dyld_exe_arch_spec,
+ &m_dyld_image_infos[exe_idx].uuid);
+ if (exe_module_sp.get())
+ {
+ // If we found the file where it purported to be, then it should
+ // be safe to load dependent images.
+ bool get_dependent_images = exe_module_sp->GetFileSpec() == m_dyld_image_infos[exe_idx].file_spec;
+
+ m_process->GetTarget().SetExecutableModule (exe_module_sp, get_dependent_images);
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// Dump a Segment to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::Segment::PutToLog (Log *log, lldb::addr_t slide) const
+{
+ if (log)
+ log->Printf("\t\t%16s [0x%16.16llx - 0x%16.16llx)", name.AsCString(""), addr + slide, addr + slide + size);
+}
+
+const DynamicLoaderMacOSXDYLD::Segment *
+DynamicLoaderMacOSXDYLD::DYLDImageInfo::FindSegment (const ConstString &name) const
+{
+ const size_t num_segments = segments.size();
+ for (size_t i=0; i<num_segments; ++i)
+ {
+ if (segments[i].name == name)
+ return &segments[i];
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Dump an image info structure to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::DYLDImageInfo::PutToLog (Log *log) const
+{
+ if (log == NULL)
+ return;
+ uint8_t *u = (uint8_t *)uuid.GetBytes();
+
+ if (address == LLDB_INVALID_ADDRESS)
+ {
+ if (u)
+ {
+ log->Printf("\t modtime=0x%8.8llx uuid=%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 path='%s/%s' (UNLOADED)",
+ mod_date,
+ 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],
+ file_spec.GetDirectory().AsCString(),
+ file_spec.GetFilename().AsCString());
+ }
+ else
+ log->Printf("\t modtime=0x%8.8llx path='%s/%s' (UNLOADED)",
+ mod_date,
+ file_spec.GetDirectory().AsCString(),
+ file_spec.GetFilename().AsCString());
+ }
+ else
+ {
+ if (u)
+ {
+ log->Printf("\taddress=0x%16.16llx modtime=0x%8.8llx uuid=%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 path='%s/%s'",
+ address,
+ mod_date,
+ 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],
+ file_spec.GetDirectory().AsCString(),
+ file_spec.GetFilename().AsCString());
+ }
+ else
+ {
+ log->Printf("\taddress=0x%16.16llx modtime=0x%8.8llx path='%s/%s'",
+ address,
+ mod_date,
+ file_spec.GetDirectory().AsCString(),
+ file_spec.GetFilename().AsCString());
+
+ }
+ for (uint32_t i=0; i<segments.size(); ++i)
+ segments[i].PutToLog(log, slide);
+ }
+}
+
+//----------------------------------------------------------------------
+// Dump the _dyld_all_image_infos members and all current image infos
+// that we have parsed to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::PutToLog(Log *log) const
+{
+ if (log == NULL)
+ return;
+
+ Mutex::Locker locker(m_mutex);
+ log->Printf("dyld_all_image_infos = { version=%d, count=%d, addr=0x%8.8llx, notify=0x%8.8llx }",
+ m_dyld_all_image_infos.version,
+ m_dyld_all_image_infos.dylib_info_count,
+ (uint64_t)m_dyld_all_image_infos.dylib_info_addr,
+ (uint64_t)m_dyld_all_image_infos.notification);
+ size_t i;
+ const size_t count = m_dyld_image_infos.size();
+ if (count > 0)
+ {
+ log->Printf("\tdyld_image_infos");
+ for (i = 0; i<count; i++)
+ m_dyld_image_infos[i].PutToLog(log);
+ }
+}
+
+//----------------------------------------------------------------------
+// Static callback function that gets called when the process state
+// changes.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::Initialize(void *baton, Process *process)
+{
+ ((DynamicLoaderMacOSXDYLD*)baton)->PrivateInitialize(process);
+}
+
+void
+DynamicLoaderMacOSXDYLD::PrivateInitialize(Process *process)
+{
+ DEBUG_PRINTF("DynamicLoaderMacOSXDYLD::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState()));
+ Clear(true);
+ m_process = process;
+}
+
+
+//----------------------------------------------------------------------
+// Static callback function that gets called when the process state
+// changes.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::ProcessStateChanged(void *baton, Process *process, StateType state)
+{
+ ((DynamicLoaderMacOSXDYLD*)baton)->PrivateProcessStateChanged(process, state);
+}
+
+bool
+DynamicLoaderMacOSXDYLD::SetNotificationBreakpoint ()
+{
+ DEBUG_PRINTF("DynamicLoaderMacOSXDYLD::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState()));
+ if (m_break_id == LLDB_INVALID_BREAK_ID)
+ {
+ if (m_dyld_all_image_infos.notification != LLDB_INVALID_ADDRESS)
+ {
+ Address so_addr;
+ // Set the notification breakpoint and install a breakpoint
+ // callback function that will get called each time the
+ // breakpoint gets hit. We will use this to track when shared
+ // libraries get loaded/unloaded.
+
+ if (m_process->ResolveLoadAddress(m_dyld_all_image_infos.notification, so_addr))
+ {
+ Breakpoint *dyld_break = m_process->GetTarget().CreateBreakpoint (so_addr, true).get();
+ dyld_break->SetCallback (DynamicLoaderMacOSXDYLD::NotifyBreakpointHit, this, true);
+ m_break_id = dyld_break->GetID();
+ }
+ }
+ }
+ return m_break_id != LLDB_INVALID_BREAK_ID;
+}
+
+//----------------------------------------------------------------------Target.h
+
+// Member function that gets called when the process state changes.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::PrivateProcessStateChanged (Process *process, StateType state)
+{
+ DEBUG_PRINTF("DynamicLoaderMacOSXDYLD::%s(%s)\n", __FUNCTION__, StateAsCString(state));
+ switch (state)
+ {
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateExited:
+ case eStateDetached:
+ Clear(false);
+ break;
+
+ case eStateStopped:
+ // Keep trying find dyld and set our notification breakpoint each time
+ // we stop until we succeed
+ if (!DidSetNotificationBreakpoint () && m_process->IsAlive())
+ {
+ if (NeedToLocateDYLD ())
+ LocateDYLD ();
+
+ SetNotificationBreakpoint ();
+ }
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ case eStateCrashed:
+ case eStateSuspended:
+ break;
+
+ default:
+ break;
+ }
+}
+
+ThreadPlanSP
+DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others)
+{
+ ThreadPlanSP thread_plan_sp;
+ StackFrame *current_frame = thread.GetStackFrameAtIndex(0).get();
+ const SymbolContext &current_context = current_frame->GetSymbolContext(eSymbolContextSymbol);
+ Symbol *current_symbol = current_context.symbol;
+
+ if (current_symbol != NULL)
+ {
+ if (current_symbol->IsTrampoline())
+ {
+ const ConstString &trampoline_name = current_symbol->GetMangled().GetName();
+ if (trampoline_name)
+ {
+ SymbolContextList target_symbols;
+ ModuleList &images = thread.GetProcess().GetTarget().GetImages();
+ images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode, target_symbols);
+ // FIXME - Make the Run to Address take multiple addresses, and
+ // run to any of them.
+ if (target_symbols.GetSize() == 1)
+ {
+ SymbolContext context;
+ AddressRange addr_range;
+ if (target_symbols.GetContextAtIndex(0, context))
+ {
+ context.GetAddressRange (eSymbolContextEverything, addr_range);
+ thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, addr_range.GetBaseAddress(), stop_others));
+ }
+ }
+ else if (target_symbols.GetSize() > 1)
+ {
+ Log *log = DynamicLoaderMacOSXDYLDLog::GetLogIfAllCategoriesSet (1);
+ if (log)
+ {
+ log->Printf ("Found more than one symbol for trampoline target: \"%s\"", trampoline_name.AsCString());
+ }
+ }
+ else
+ {
+ Log *log = DynamicLoaderMacOSXDYLDLog::GetLogIfAllCategoriesSet (1);
+ if (log)
+ {
+ log->Printf ("Could not find symbol for trampoline target: \"%s\"", trampoline_name.AsCString());
+ }
+ }
+ }
+ }
+ }
+
+ if (thread_plan_sp == NULL && m_objc_trampoline_handler_ap.get())
+ thread_plan_sp = m_objc_trampoline_handler_ap->GetStepThroughDispatchPlan (thread, stop_others);
+
+ return thread_plan_sp;
+}
+
+void
+DynamicLoaderMacOSXDYLD::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DynamicLoaderMacOSXDYLD::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+DynamicLoaderMacOSXDYLD::GetPluginNameStatic()
+{
+ return "dynamic-loader.macosx-dyld";
+}
+
+const char *
+DynamicLoaderMacOSXDYLD::GetPluginDescriptionStatic()
+{
+ return "Dynamic loader plug-in that watches for shared library loads/unloads in MacOSX user processes.";
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+DynamicLoaderMacOSXDYLD::GetPluginName()
+{
+ return "DynamicLoaderMacOSXDYLD";
+}
+
+const char *
+DynamicLoaderMacOSXDYLD::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+DynamicLoaderMacOSXDYLD::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+DynamicLoaderMacOSXDYLD::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+DynamicLoaderMacOSXDYLD::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+DynamicLoaderMacOSXDYLD::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h
new file mode 100644
index 00000000000..724a8b6bd6d
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h
@@ -0,0 +1,360 @@
+//===-- DynamicLoaderMacOSXDYLD.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_DynamicLoaderMacOSXDYLD_h_
+#define liblldb_DynamicLoaderMacOSXDYLD_h_
+
+// C Includes
+#include <mach-o/loader.h>
+
+// C++ Includes
+#include <map>
+#include <vector>
+#include <string>
+
+// Other libraries and framework includes
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+#include "ObjCTrampolineHandler.h"
+
+class DynamicLoaderMacOSXDYLD : public lldb_private::DynamicLoader
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance (lldb_private::Process *process);
+
+ DynamicLoaderMacOSXDYLD (lldb_private::Process *process);
+
+ virtual
+ ~DynamicLoaderMacOSXDYLD ();
+ //------------------------------------------------------------------
+ /// Called after attaching a process.
+ ///
+ /// Allow DynamicLoader plug-ins to execute some code after
+ /// attaching to a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidAttach ();
+
+ virtual void
+ DidLaunch ();
+
+ //------------------------------------------------------------------
+ // Process::Notifications callback functions
+ //------------------------------------------------------------------
+ static void
+ Initialize (void *baton,
+ lldb_private::Process *process);
+
+ static void
+ ProcessStateChanged (void *baton,
+ lldb_private::Process *process,
+ lldb::StateType state);
+
+ virtual lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan (lldb_private::Thread &thread,
+ bool stop_others);
+
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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:
+ void
+ PrivateInitialize (lldb_private::Process *process);
+
+ void
+ PrivateProcessStateChanged (lldb_private::Process *process,
+ lldb::StateType state);
+ bool
+ LocateDYLD ();
+
+ bool
+ DidSetNotificationBreakpoint () const;
+
+ void
+ Clear (bool clear_process);
+
+ void
+ PutToLog (lldb_private::Log *log) const;
+
+ bool
+ ReadDYLDInfoFromMemoryAndSetNotificationCallback (lldb::addr_t addr);
+
+ uint32_t
+ UpdateAllImageInfos ();
+
+ static bool
+ NotifyBreakpointHit (void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+ void
+ UpdateAllImageInfosHeaderAndLoadCommands ();
+
+ bool
+ UpdateCommPageLoadAddress (lldb_private::Module *module);
+
+ uint32_t
+ AddrByteSize()
+ {
+ switch (m_dyld.header.magic)
+ {
+ case MH_MAGIC:
+ case MH_CIGAM:
+ return 4;
+
+ case MH_MAGIC_64:
+ case MH_CIGAM_64:
+ return 8;
+
+ default:
+ break;
+ }
+ return 0;
+ }
+
+ static lldb::ByteOrder
+ GetByteOrderFromMagic (uint32_t magic)
+ {
+ switch (magic)
+ {
+ case MH_MAGIC:
+ case MH_MAGIC_64:
+ return lldb::eByteOrderHost;
+
+ case MH_CIGAM:
+ case MH_CIGAM_64:
+ if (lldb::eByteOrderHost == lldb::eByteOrderBig)
+ return lldb::eByteOrderLittle;
+ else
+ return lldb::eByteOrderBig;
+
+ default:
+ break;
+ }
+ return lldb::eByteOrderInvalid;
+ }
+
+ bool
+ ReadMachHeader (lldb::addr_t addr,
+ struct mach_header *header,
+ lldb_private::DataExtractor *load_command_data);
+ class Segment
+ {
+ public:
+
+ Segment() :
+ name(),
+ addr(LLDB_INVALID_ADDRESS),
+ size(0)
+ {
+ }
+
+ lldb_private::ConstString name;
+ lldb::addr_t addr;
+ lldb::addr_t size;
+
+ bool
+ operator==(const Segment& rhs) const
+ {
+ return name == rhs.name && addr == rhs.addr && size == rhs.size;
+ }
+
+ void
+ PutToLog (lldb_private::Log *log,
+ lldb::addr_t slide) const;
+
+ };
+
+ struct DYLDImageInfo
+ {
+ lldb::addr_t address; // Address of mach header for this dylib
+ lldb::addr_t slide; // The amount to slide all segments by if there is a global slide.
+ lldb::addr_t mod_date; // Modification date for this dylib
+ lldb_private::FileSpec file_spec; // Resolved path for this dylib
+ lldb_private::UUID uuid; // UUID for this dylib if it has one, else all zeros
+ struct mach_header header; // The mach header for this image
+ std::vector<Segment> segments; // All segment vmaddr and vmsize pairs for this executable (from memory of inferior)
+
+ DYLDImageInfo() :
+ address(LLDB_INVALID_ADDRESS),
+ slide(0),
+ mod_date(0),
+ file_spec(),
+ uuid(),
+ header(),
+ segments()
+ {
+ }
+
+ void
+ Clear(bool load_cmd_data_only)
+ {
+ if (!load_cmd_data_only)
+ {
+ address = LLDB_INVALID_ADDRESS;
+ slide = 0;
+ mod_date = 0;
+ file_spec.Clear();
+ ::bzero (&header, sizeof(header));
+ }
+ uuid.Clear();
+ segments.clear();
+ }
+
+ bool
+ operator == (const DYLDImageInfo& rhs) const
+ {
+ return address == rhs.address
+ && slide == rhs.slide
+ && mod_date == rhs.mod_date
+ && file_spec == rhs.file_spec
+ && uuid == rhs.uuid
+ && memcmp(&header, &rhs.header, sizeof(header)) == 0
+ && segments == rhs.segments;
+ }
+
+ bool
+ UUIDValid() const
+ {
+ return uuid.IsValid();
+ }
+
+ const Segment *
+ FindSegment (const lldb_private::ConstString &name) const;
+
+ void
+ PutToLog (lldb_private::Log *log) const;
+
+ typedef std::vector<DYLDImageInfo> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ };
+
+ struct DYLDAllImageInfos
+ {
+ uint32_t version;
+ uint32_t dylib_info_count; // Version >= 1
+ lldb::addr_t dylib_info_addr; // Version >= 1
+ lldb::addr_t notification; // Version >= 1
+ bool processDetachedFromSharedRegion; // Version >= 1
+ bool libSystemInitialized; // Version >= 2
+ lldb::addr_t dyldImageLoadAddress; // Version >= 2
+
+ DYLDAllImageInfos() :
+ version (0),
+ dylib_info_count (0),
+ dylib_info_addr (LLDB_INVALID_ADDRESS),
+ notification (LLDB_INVALID_ADDRESS),
+ processDetachedFromSharedRegion (false),
+ libSystemInitialized (false),
+ dyldImageLoadAddress (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ void
+ Clear()
+ {
+ version = 0;
+ dylib_info_count = 0;
+ dylib_info_addr = LLDB_INVALID_ADDRESS;
+ notification = LLDB_INVALID_ADDRESS;
+ processDetachedFromSharedRegion = false;
+ libSystemInitialized = false;
+ dyldImageLoadAddress = LLDB_INVALID_ADDRESS;
+ }
+
+ bool
+ IsValid() const
+ {
+ return version >= 1 || version <= 6;
+ }
+ };
+
+ void
+ RegisterNotificationCallbacks();
+
+ void
+ UnregisterNotificationCallbacks();
+
+ uint32_t
+ ParseLoadCommands (const lldb_private::DataExtractor& data,
+ struct DYLDImageInfo& dylib_info,
+ lldb_private::FileSpec *lc_id_dylinker);
+
+ bool
+ UpdateImageLoadAddress(lldb_private::Module *module,
+ struct DYLDImageInfo& info);
+
+ bool
+ UnloadImageLoadAddress (lldb_private::Module *module,
+ struct DYLDImageInfo& info);
+
+ bool
+ NeedToLocateDYLD () const;
+
+ bool
+ SetNotificationBreakpoint ();
+
+ bool
+ ReadAllImageInfosStructure ();
+
+ DYLDImageInfo m_dyld; // Info about the curent dyld being used
+ lldb::addr_t m_dyld_all_image_infos_addr;
+ DYLDAllImageInfos m_dyld_all_image_infos;
+ lldb::user_id_t m_break_id;
+ DYLDImageInfo::collection m_dyld_image_infos; // Current shared libraries information
+ mutable lldb_private::Mutex m_mutex;
+ lldb_private::Process::Notifications m_notification_callbacks;
+ std::auto_ptr<lldb_private::ObjCTrampolineHandler> m_objc_trampoline_handler_ap;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (DynamicLoaderMacOSXDYLD);
+};
+
+#endif // liblldb_DynamicLoaderMacOSXDYLD_h_
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.cpp
new file mode 100644
index 00000000000..946c8f9310c
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.cpp
@@ -0,0 +1,72 @@
+//===-- DynamicLoaderMacOSXDYLDLog.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DynamicLoaderMacOSXDYLDLog.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb_private;
+
+static Log *
+LogAccessor (bool get, Log *log)
+{
+ static Log* g_log = NULL; // Leak for now as auto_ptr was being cleaned up
+ // by global constructors before other threads
+ // were done with it.
+ if (get)
+ {
+// // Debug code below for enabling logging by default
+// if (g_log == NULL)
+// {
+// g_log = new Log("/dev/stdout", false);
+// g_log->GetMask().SetAllFlagBits(0xffffffffu);
+// g_log->GetOptions().Set(LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_THREAD_NAME);
+// }
+ }
+ else
+ {
+ if (g_log)
+ delete g_log;
+ g_log = log;
+ }
+
+ return g_log;
+}
+
+Log *
+DynamicLoaderMacOSXDYLDLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log = LogAccessor (true, NULL);
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().GetAllFlagBits();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+void
+DynamicLoaderMacOSXDYLDLog::SetLog (Log *log)
+{
+ LogAccessor (false, log);
+}
+
+
+void
+DynamicLoaderMacOSXDYLDLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log = DynamicLoaderMacOSXDYLDLog::GetLogIfAllCategoriesSet (mask);
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.h b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.h
new file mode 100644
index 00000000000..9282ba57647
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLDLog.h
@@ -0,0 +1,34 @@
+//===-- DynamicLoaderMacOSXDYLDLog.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_DynamicLoaderMacOSXDYLDLog_h_
+#define liblldb_DynamicLoaderMacOSXDYLDLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+#include "lldb/lldb-private.h"
+
+// Project includes
+
+class DynamicLoaderMacOSXDYLDLog
+{
+public:
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet (uint32_t mask);
+
+ static void
+ SetLog (lldb_private::Log *log);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // liblldb_DynamicLoaderMacOSXDYLDLog_h_
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.cpp
new file mode 100644
index 00000000000..169dc89c791
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.cpp
@@ -0,0 +1,328 @@
+//===-- ObjCTrampolineHandler.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjCTrampolineHandler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "ThreadPlanStepThroughObjCTrampoline.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const ObjCTrampolineHandler::DispatchFunction
+ObjCTrampolineHandler::g_dispatch_functions[] =
+{
+ // NAME STRET SUPER FIXUP TYPE
+ {"objc_msgSend", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSend_fixup", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpToFix },
+ {"objc_msgSend_fixedup", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpFixed },
+ {"objc_msgSend_stret", true, false, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSend_stret_fixup", true, false, ObjCTrampolineHandler::DispatchFunction::eFixUpToFix },
+ {"objc_msgSend_stret_fixedup", true, false, ObjCTrampolineHandler::DispatchFunction::eFixUpFixed },
+ {"objc_msgSend_fpret", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSend_fpret_fixup", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpToFix },
+ {"objc_msgSend_fpret_fixedup", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpFixed },
+ {"objc_msgSend_fp2ret", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSend_fp2ret_fixup", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpToFix },
+ {"objc_msgSend_fp2ret_fixedup", false, false, ObjCTrampolineHandler::DispatchFunction::eFixUpFixed },
+ {"objc_msgSendSuper", false, true, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSendSuper_stret", true, true, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSendSuper2", false, true, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSendSuper2_fixup", false, true, ObjCTrampolineHandler::DispatchFunction::eFixUpToFix },
+ {"objc_msgSendSuper2_fixedup", false, true, ObjCTrampolineHandler::DispatchFunction::eFixUpFixed },
+ {"objc_msgSendSuper2_stret", true, true, ObjCTrampolineHandler::DispatchFunction::eFixUpNone },
+ {"objc_msgSendSuper2_stret_fixup", true, true, ObjCTrampolineHandler::DispatchFunction::eFixUpToFix },
+ {"objc_msgSendSuper2_stret_fixedup", true, true, ObjCTrampolineHandler::DispatchFunction::eFixUpFixed },
+ {NULL}
+};
+
+bool
+ObjCTrampolineHandler::ModuleIsObjCLibrary (const ModuleSP &module_sp)
+{
+ const FileSpec &module_file_spec = module_sp->GetFileSpec();
+ static ConstString ObjCName ("libobjc.A.dylib");
+
+ if (module_file_spec)
+ {
+ if (module_file_spec.GetFilename() == ObjCName)
+ return true;
+ }
+
+ return false;
+}
+
+ObjCTrampolineHandler::ObjCTrampolineHandler (ProcessSP process_sp, ModuleSP objc_module) :
+ m_process_sp (process_sp),
+ m_objc_module_sp (objc_module),
+ m_impl_fn_addr (LLDB_INVALID_ADDRESS),
+ m_impl_stret_fn_addr (LLDB_INVALID_ADDRESS)
+{
+ // Look up the known resolution functions:
+
+ ConstString get_impl_name("class_getMethodImplementation");
+ ConstString get_impl_stret_name("class_getMethodImplementation_stret");
+
+ const Symbol *class_getMethodImplementation = m_objc_module_sp->FindFirstSymbolWithNameAndType (get_impl_name, eSymbolTypeCode);
+ const Symbol *class_getMethodImplementation_stret = m_objc_module_sp->FindFirstSymbolWithNameAndType (get_impl_stret_name, eSymbolTypeCode);
+
+ if (class_getMethodImplementation)
+ m_impl_fn_addr = class_getMethodImplementation->GetValue().GetLoadAddress(m_process_sp.get());
+ if (class_getMethodImplementation_stret)
+ m_impl_stret_fn_addr = class_getMethodImplementation_stret->GetValue().GetLoadAddress(m_process_sp.get());
+
+ // FIXME: Do some kind of logging here.
+ if (m_impl_fn_addr == LLDB_INVALID_ADDRESS || m_impl_stret_fn_addr == LLDB_INVALID_ADDRESS)
+ return;
+
+ // Look up the addresses for the objc dispatch functions and cache them. For now I'm inspecting the symbol
+ // names dynamically to figure out how to dispatch to them. If it becomes more complicated than this we can
+ // turn the g_dispatch_functions char * array into a template table, and populate the DispatchFunction map
+ // from there.
+
+ for (int i = 0; g_dispatch_functions[i].name != NULL; i++)
+ {
+ ConstString name_const_str(g_dispatch_functions[i].name);
+ const Symbol *msgSend_symbol = m_objc_module_sp->FindFirstSymbolWithNameAndType (name_const_str, eSymbolTypeCode);
+ if (msgSend_symbol)
+ {
+ // FixMe: Make g_dispatch_functions static table of DisptachFunctions, and have the map be address->index.
+ // Problem is we also need to lookup the dispatch function. For now we could have a side table of stret & non-stret
+ // dispatch functions. If that's as complex as it gets, we're fine.
+
+ lldb::addr_t sym_addr = msgSend_symbol->GetValue().GetLoadAddress(m_process_sp.get());
+
+ m_msgSend_map.insert(std::pair<lldb::addr_t, int>(sym_addr, i));
+ }
+ }
+}
+
+ThreadPlanSP
+ObjCTrampolineHandler::GetStepThroughDispatchPlan (Thread &thread, bool stop_others)
+{
+ ThreadPlanSP ret_plan_sp;
+ lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
+
+ MsgsendMap::iterator pos;
+ pos = m_msgSend_map.find (curr_pc);
+ if (pos != m_msgSend_map.end())
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ const DispatchFunction *this_dispatch = &g_dispatch_functions[(*pos).second];
+
+ lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
+
+ Process *process = thread.CalculateProcess();
+ const ABI *abi = process->GetABI();
+ if (abi == NULL)
+ return ret_plan_sp;
+
+ Target *target = thread.CalculateTarget();
+
+ // FIXME: Since neither the value nor the Clang QualType know their ASTContext,
+ // we have to make sure the type we put in our value list comes from the same ASTContext
+ // the ABI will use to get the argument values. THis is the bottom-most frame's module.
+
+ ClangASTContext *clang_ast_context = target->GetScratchClangASTContext();
+ ValueList argument_values;
+ Value input_value;
+ void *clang_void_ptr_type = clang_ast_context->GetVoidPtrType(false);
+ input_value.SetValueType (Value::eValueTypeScalar);
+ input_value.SetContext (Value::eContextTypeOpaqueClangQualType, clang_void_ptr_type);
+
+ int obj_index;
+ int sel_index;
+
+ // If this is a struct return dispatch, then the first argument is the
+ // return struct pointer, and the object is the second, and the selector is the third.
+ // Otherwise the object is the first and the selector the second.
+ if (this_dispatch->stret_return)
+ {
+ obj_index = 1;
+ sel_index = 2;
+ argument_values.PushValue(input_value);
+ argument_values.PushValue(input_value);
+ argument_values.PushValue(input_value);
+ }
+ else
+ {
+ obj_index = 0;
+ sel_index = 1;
+ argument_values.PushValue(input_value);
+ argument_values.PushValue(input_value);
+ }
+
+
+ bool success = abi->GetArgumentValues (thread, argument_values);
+ if (!success)
+ return ret_plan_sp;
+
+ // Okay, the first value here is the object, we actually want the class of that object.
+ // For now we're just going with the ISA.
+ // FIXME: This should really be the return value of [object class] to properly handle KVO interposition.
+
+ Value isa_value(*(argument_values.GetValueAtIndex(obj_index)));
+
+ // This is a little cheesy, but since object->isa is the first field,
+ // making the object value a load address value and resolving it will get
+ // the pointer sized data pointed to by that value...
+ ExecutionContext exec_ctx;
+ thread.Calculate (exec_ctx);
+
+ isa_value.SetValueType(Value::eValueTypeLoadAddress);
+ isa_value.ResolveValue(&exec_ctx, clang_ast_context->getASTContext());
+
+ if (this_dispatch->fixedup == DispatchFunction::eFixUpFixed)
+ {
+ // For the FixedUp method the Selector is actually a pointer to a
+ // structure, the second field of which is the selector number.
+ Value *sel_value = argument_values.GetValueAtIndex(sel_index);
+ sel_value->GetScalar() += process->GetAddressByteSize();
+ sel_value->SetValueType(Value::eValueTypeLoadAddress);
+ sel_value->ResolveValue(&exec_ctx, clang_ast_context->getASTContext());
+ }
+ else if (this_dispatch->fixedup == DispatchFunction::eFixUpToFix)
+ {
+ // FIXME: If the method dispatch is not "fixed up" then the selector is actually a
+ // pointer to the string name of the selector. We need to look that up...
+ // For now I'm going to punt on that and just return no plan.
+ if (log)
+ log->Printf ("Punting on stepping into un-fixed-up method dispatch.");
+ return ret_plan_sp;
+ }
+
+ // FIXME: If this is a dispatch to the super-class, we need to get the super-class from
+ // the class, and disaptch to that instead.
+ // But for now I just punt and return no plan.
+ if (this_dispatch->is_super)
+ {
+ if (log)
+ log->Printf ("Punting on stepping into super method dispatch.");
+ return ret_plan_sp;
+ }
+
+ ValueList dispatch_values;
+ dispatch_values.PushValue (isa_value);
+ dispatch_values.PushValue(*(argument_values.GetValueAtIndex(sel_index)));
+
+ if (log)
+ {
+ log->Printf("Resolving method call for class - 0x%llx and selector - 0x%llx",
+ dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
+ dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong());
+ }
+
+ lldb::addr_t impl_addr = LookupInCache (dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
+ dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong());
+
+ if (impl_addr == LLDB_INVALID_ADDRESS)
+ {
+
+ Address resolve_address(NULL, this_dispatch->stret_return ? m_impl_stret_fn_addr : m_impl_fn_addr);
+
+ StreamString errors;
+ {
+ // Scope for mutex locker:
+ Mutex::Locker (m_impl_function_mutex);
+ if (!m_impl_function.get())
+ {
+ m_impl_function.reset(new ClangFunction(process->GetTargetTriple().GetCString(),
+ clang_ast_context,
+ clang_void_ptr_type,
+ resolve_address,
+ dispatch_values));
+
+ unsigned num_errors = m_impl_function->CompileFunction(errors);
+ if (num_errors)
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf ("Error compiling function: \"%s\".", errors.GetData());
+ return ret_plan_sp;
+ }
+
+ errors.Clear();
+ if (!m_impl_function->WriteFunctionWrapper(exec_ctx, errors))
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
+ return ret_plan_sp;
+ }
+ }
+
+ }
+
+ errors.Clear();
+
+ // Now write down the argument values for this call.
+ lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+ if (!m_impl_function->WriteFunctionArguments (exec_ctx, args_addr, resolve_address, dispatch_values, errors))
+ return ret_plan_sp;
+
+ ret_plan_sp.reset (new ThreadPlanStepThroughObjCTrampoline (thread, this, args_addr,
+ argument_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
+ dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
+ dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong(),
+ stop_others));
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Found implementation address in cache: 0x%llx", impl_addr);
+
+ ret_plan_sp.reset (new ThreadPlanRunToAddress (thread, impl_addr, stop_others));
+ }
+ }
+
+ return ret_plan_sp;
+}
+
+void
+ObjCTrampolineHandler::AddToCache (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%llx selector 0x%llx implementation 0x%llx.", class_addr, selector, impl_addr);
+ }
+ m_impl_cache.insert (std::pair<ClassAndSel,lldb::addr_t> (ClassAndSel(class_addr, selector), impl_addr));
+}
+
+lldb::addr_t
+ObjCTrampolineHandler::LookupInCache (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;
+}
+
+ClangFunction *
+ObjCTrampolineHandler::GetLookupImplementationWrapperFunction ()
+{
+ return m_impl_function.get();
+}
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.h b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.h
new file mode 100644
index 00000000000..bc06d267d2f
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ObjCTrampolineHandler.h
@@ -0,0 +1,133 @@
+//===-- ObjCTrampolineHandler.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_ObjCTrampolineHandler_h_
+#define lldb_ObjCTrampolineHandler_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <string>
+// Other libraries and framework includes
+// Project includes
+#include "lldb.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Host/Mutex.h"
+
+
+namespace lldb_private
+{
+using namespace lldb;
+
+class ObjCTrampolineHandler {
+public:
+
+ ObjCTrampolineHandler (ProcessSP process_sp, ModuleSP objc_module_sp);
+
+ ~ObjCTrampolineHandler() {}
+
+ static bool ModuleIsObjCLibrary (const ModuleSP &module_sp);
+
+ ThreadPlanSP
+ GetStepThroughDispatchPlan (Thread &thread, bool stop_others);
+
+ void
+ AddToCache (lldb::addr_t class_addr, lldb::addr_t sel, lldb::addr_t impl_addr);
+
+ lldb::addr_t
+ LookupInCache (lldb::addr_t class_addr, lldb::addr_t sel);
+
+ ClangFunction *
+ GetLookupImplementationWrapperFunction ();
+
+
+ struct DispatchFunction {
+ public:
+ typedef enum
+ {
+ eFixUpNone,
+ eFixUpFixed,
+ eFixUpToFix
+ } FixUpState;
+
+ const char *name;
+ bool stret_return;
+ bool is_super;
+ FixUpState fixedup;
+ };
+
+private:
+ static const DispatchFunction g_dispatch_functions[];
+
+ typedef std::map<lldb::addr_t, int> MsgsendMap; // This table maps an dispatch fn address to the index in g_dispatch_functions
+ MsgsendMap m_msgSend_map;
+ ProcessSP m_process_sp;
+ ModuleSP m_objc_module_sp;
+ lldb::addr_t get_impl_addr;
+ std::auto_ptr<ClangFunction> m_impl_function;
+ Mutex m_impl_function_mutex;
+ lldb::addr_t m_impl_fn_addr;
+ lldb::addr_t m_impl_stret_fn_addr;
+
+
+ // 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;
+ MsgImplMap m_impl_cache;
+
+};
+
+}; // using namespace lldb_private
+
+#endif // lldb_ObjCTrampolineHandler_h_
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.cpp
new file mode 100644
index 00000000000..a0cb0a86f18
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.cpp
@@ -0,0 +1,151 @@
+//===-- ThreadPlanStepThroughObjCTrampoline.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 "ThreadPlanStepThroughObjCTrampoline.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepThroughObjCTrampoline constructor
+//----------------------------------------------------------------------
+ThreadPlanStepThroughObjCTrampoline::ThreadPlanStepThroughObjCTrampoline(
+ Thread &thread,
+ ObjCTrampolineHandler *trampoline_handler,
+ lldb::addr_t args_addr,
+ lldb::addr_t object_ptr,
+ lldb::addr_t class_ptr,
+ lldb::addr_t sel_ptr,
+ bool stop_others) :
+ ThreadPlan ("MacOSX Step through ObjC Trampoline", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_objc_trampoline_handler (trampoline_handler),
+ m_impl_function (trampoline_handler->GetLookupImplementationWrapperFunction()),
+ m_args_addr (args_addr),
+ m_object_ptr (object_ptr),
+ m_class_ptr (class_ptr),
+ m_sel_ptr (sel_ptr),
+ m_stop_others (stop_others)
+{
+
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ThreadPlanStepThroughObjCTrampoline::~ThreadPlanStepThroughObjCTrampoline()
+{
+}
+
+void
+ThreadPlanStepThroughObjCTrampoline::DidPush ()
+{
+ StreamString errors;
+ ExecutionContext exc_context;
+ m_thread.Calculate(exc_context);
+ m_func_sp.reset(m_impl_function->GetThreadPlanToCallFunction (exc_context, m_args_addr, errors, m_stop_others));
+ m_func_sp->SetPrivate(true);
+ m_thread.QueueThreadPlan (m_func_sp, false);
+}
+
+void
+ThreadPlanStepThroughObjCTrampoline::GetDescription (Stream *s,
+ lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf("Step through ObjC trampoline");
+ else
+ {
+ s->Printf ("Stepping to implementation of ObjC method - obj: 0x%llx class: 0x%llx selector: 0x%llx",
+ m_object_ptr, m_class_ptr, m_sel_ptr);
+ }
+}
+
+bool
+ThreadPlanStepThroughObjCTrampoline::ValidatePlan (Stream *error)
+{
+ return true;
+}
+
+bool
+ThreadPlanStepThroughObjCTrampoline::PlanExplainsStop ()
+{
+ // This plan should actually never stop when it is on the top of the plan
+ // stack, since it does all it's running in client plans.
+ return false;
+}
+
+lldb::StateType
+ThreadPlanStepThroughObjCTrampoline::RunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanStepThroughObjCTrampoline::ShouldStop (Event *event_ptr)
+{
+ if (m_func_sp.get() == NULL || m_thread.IsThreadPlanDone(m_func_sp.get()))
+ {
+ m_func_sp.reset();
+ if (!m_run_to_sp)
+ {
+ Value target_addr_value;
+ ExecutionContext exc_context;
+ m_thread.Calculate(exc_context);
+ m_impl_function->FetchFunctionResults (exc_context, m_args_addr, target_addr_value);
+ m_impl_function->DeallocateFunctionResults(exc_context, m_args_addr);
+ lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong();
+ Address target_address(NULL, target_addr);
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf("Running to ObjC method implementation: 0x%llx", target_addr);
+
+ m_objc_trampoline_handler->AddToCache (m_class_ptr, m_sel_ptr, target_addr);
+
+ // Extract the target address from the value:
+
+ m_run_to_sp.reset(new ThreadPlanRunToAddress(m_thread, target_address, m_stop_others));
+ m_thread.QueueThreadPlan(m_run_to_sp, false);
+ m_run_to_sp->SetPrivate(true);
+ return false;
+ }
+ else if (m_thread.IsThreadPlanDone(m_run_to_sp.get()))
+ {
+ SetPlanComplete();
+ return true;
+ }
+ }
+ return false;
+}
+
+// The base class MischiefManaged does some cleanup - so you have to call it
+// in your MischiefManaged derived class.
+bool
+ThreadPlanStepThroughObjCTrampoline::MischiefManaged ()
+{
+ if (IsPlanComplete())
+ return true;
+ else
+ return false;
+}
+
+bool
+ThreadPlanStepThroughObjCTrampoline::WillStop()
+{
+ return true;
+}
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.h b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.h
new file mode 100644
index 00000000000..8033718277e
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.h
@@ -0,0 +1,94 @@
+//===-- ThreadPlanStepThroughObjCTrampoline.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_ThreadPlanStepThroughObjCTrampoline_h_
+#define lldb_ThreadPlanStepThroughObjCTrampoline_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb-types.h"
+#include "lldb-enumerations.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "ObjCTrampolineHandler.h"
+
+namespace lldb_private
+{
+
+class ThreadPlanStepThroughObjCTrampoline : public ThreadPlan
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ThreadPlanStepThroughObjCTrampoline(Thread &thread,
+ ObjCTrampolineHandler *trampoline_handler,
+ lldb::addr_t args_addr,
+ lldb::addr_t object_ptr,
+ lldb::addr_t class_ptr,
+ lldb::addr_t sel_ptr,
+ bool stop_others);
+
+ virtual ~ThreadPlanStepThroughObjCTrampoline();
+
+ virtual void
+ GetDescription (Stream *s,
+ lldb::DescriptionLevel level);
+
+ virtual bool
+ ValidatePlan (Stream *error);
+
+ virtual bool
+ PlanExplainsStop ();
+
+
+ virtual lldb::StateType
+ RunState ();
+
+ virtual bool
+ ShouldStop (Event *event_ptr);
+
+ // The base class MischiefManaged does some cleanup - so you have to call it
+ // in your MischiefManaged derived class.
+ virtual bool
+ MischiefManaged ();
+
+ virtual void
+ DidPush();
+
+ virtual bool
+ WillStop();
+
+
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from ThreadPlanStepThroughObjCTrampoline can see and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For ThreadPlanStepThroughObjCTrampoline only
+ //------------------------------------------------------------------
+ ThreadPlanSP m_func_sp; // This is the function call plan. We fill it at start, then set it
+ // to NULL when this plan is done. That way we know to go to:
+ lldb::addr_t m_args_addr; // Stores the address for our step through function result structure.
+ ThreadPlanSP m_run_to_sp; // The plan that runs to the target.
+ bool m_stop_others;
+ ObjCTrampolineHandler *m_objc_trampoline_handler;
+ ClangFunction *m_impl_function; // This is a pointer to a impl function that
+ // is owned by the client that pushes this plan.
+ lldb::addr_t m_object_ptr;
+ lldb::addr_t m_class_ptr;
+ lldb::addr_t m_sel_ptr;
+};
+
+}; // namespace lldb_private
+#endif // lldb_ThreadPlanStepThroughObjCTrampoline_h_
diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
new file mode 100644
index 00000000000..c2fb2a552b3
--- /dev/null
+++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -0,0 +1,428 @@
+//===-- 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/Stream.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.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;
+}
+
+uint32_t
+ObjectContainerBSDArchive::Object::Extract (const DataExtractor& data, uint32_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(AR_EFMT1) == 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_INDEX32;
+}
+
+ObjectContainerBSDArchive::Archive::Archive
+(
+ const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &time
+) :
+ m_arch (arch),
+ m_time (time),
+ m_objects()
+{
+}
+
+ObjectContainerBSDArchive::Archive::~Archive ()
+{
+}
+
+size_t
+ObjectContainerBSDArchive::Archive::ParseObjects (DataExtractor &data)
+{
+ std::string str;
+ uint32_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_INDEX32)
+ break;
+ uint32_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 UniqueCStringMap<uint32_t>::Entry *match = m_object_name_to_index_map.FindFirstValueForName (object_name.GetCString());
+ if (match)
+ return &m_objects[match->value];
+ return NULL;
+}
+
+
+ObjectContainerBSDArchive::Archive::shared_ptr
+ObjectContainerBSDArchive::Archive::FindCachedArchive (const FileSpec &file, const ArchSpec &arch, const TimeValue &time)
+{
+ Mutex::Locker locker(Archive::GetArchiveCacheMutex ());
+ shared_ptr archive_sp;
+ Archive::Map &archive_map = Archive::GetArchiveCache ();
+ Archive::Map::iterator pos;
+ for (pos = archive_map.find (file); pos != archive_map.end() && pos->first == file; ++pos)
+ {
+ if (pos->second->GetArchitecture() == arch &&
+ pos->second->GetModificationTime() == time)
+ {
+ archive_sp = pos->second;
+ }
+ }
+ return archive_sp;
+}
+
+ObjectContainerBSDArchive::Archive::shared_ptr
+ObjectContainerBSDArchive::Archive::ParseAndCacheArchiveForFile
+(
+ const FileSpec &file,
+ const ArchSpec &arch,
+ const TimeValue &time,
+ DataExtractor &data
+)
+{
+ shared_ptr archive_sp(new Archive (arch, time));
+ if (archive_sp)
+ {
+ if (archive_sp->ParseObjects (data) > 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);
+}
+
+void
+ObjectContainerBSDArchive::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+ObjectContainerBSDArchive::GetPluginNameStatic()
+{
+ return "object-container.bsd-archive";
+}
+
+const char *
+ObjectContainerBSDArchive::GetPluginDescriptionStatic()
+{
+ return "BSD Archive object container reader.";
+}
+
+
+ObjectContainer *
+ObjectContainerBSDArchive::CreateInstance
+(
+ Module* module,
+ DataBufferSP& dataSP,
+ const FileSpec *file,
+ addr_t offset,
+ addr_t length)
+{
+ if (file)
+ {
+ std::string object;
+
+ Archive::shared_ptr archive_sp (Archive::FindCachedArchive (*file, module->GetArchitecture(), module->GetModificationTime()));
+
+ if (archive_sp)
+ {
+ // We already have this archive in our cache, use it
+ std::auto_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module, dataSP, file, offset, length));
+ if (container_ap.get())
+ {
+ container_ap->SetArchive (archive_sp);
+ return container_ap.release();
+ }
+ }
+
+ if (dataSP)
+ {
+ if (ObjectContainerBSDArchive::MagicBytesMatch(dataSP))
+ {
+ // Read everything since we need that in order to index all the
+ // objects in the archive
+ dataSP = file->ReadFileContents(offset, length);
+
+ std::auto_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module, dataSP, file, offset, length));
+ if (container_ap->ParseHeader())
+ return container_ap.release();
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+bool
+ObjectContainerBSDArchive::MagicBytesMatch (DataBufferSP& dataSP)
+{
+ DataExtractor data(dataSP, eByteOrderHost, 4);
+ 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
+(
+ Module* module,
+ DataBufferSP& dataSP,
+ const lldb_private::FileSpec *file,
+ lldb::addr_t offset,
+ lldb::addr_t size
+) :
+ ObjectContainer (module, file, offset, size, dataSP),
+ 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)
+ {
+ m_archive_sp = Archive::ParseAndCacheArchiveForFile (m_file,
+ m_module->GetArchitecture(),
+ m_module->GetModificationTime(),
+ m_data);
+ // The archive might be huge, so clear "m_data" to free up the
+ // memory since it will contain the entire file (possibly more than
+ // one architecture slice). We already have an index of all objects
+ // in the file, so we will be ready to serve up those objects.
+ m_data.Clear();
+ }
+ }
+ return m_archive_sp.get() != NULL;
+}
+
+void
+ObjectContainerBSDArchive::Dump (Stream *s) const
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ const size_t num_archs = GetNumArchitectures();
+ const size_t num_objects = GetNumObjects();
+ s->Printf("ObjectContainerBSDArchive, num_archs = %u, num_objects = %u", 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", arch.AsCString());
+ }
+ for (i=0; i<num_objects; i++)
+ {
+ s->Indent();
+ s->Printf("object[%u] = %s\n", GetObjectNameAtIndex (i));
+ }
+ s->IndentLess();
+ s->EOL();
+}
+
+ObjectFile *
+ObjectContainerBSDArchive::GetObjectFile (const FileSpec *file)
+{
+ if (m_module->GetObjectName() && m_archive_sp)
+ {
+ Object *object = m_archive_sp->FindObject (m_module->GetObjectName());
+ if (object)
+ return ObjectFile::FindPlugin (m_module, file, m_offset + object->ar_file_offset, object->ar_file_size);
+ }
+ return NULL;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ObjectContainerBSDArchive::GetPluginName()
+{
+ return "object-container.bsd-archive";
+}
+
+const char *
+ObjectContainerBSDArchive::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectContainerBSDArchive::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ObjectContainerBSDArchive::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ObjectContainerBSDArchive::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ObjectContainerBSDArchive::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
+
diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
new file mode 100644
index 00000000000..88aba019ead
--- /dev/null
+++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
@@ -0,0 +1,183 @@
+//===-- 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/Core/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 const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectContainer *
+ CreateInstance (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec *file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ static bool
+ MagicBytesMatch (lldb::DataBufferSP& dataSP);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ ObjectContainerBSDArchive (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec *file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ virtual
+ ~ObjectContainerBSDArchive();
+
+ virtual bool
+ ParseHeader ();
+
+ virtual void
+ Dump (lldb_private::Stream *s) const;
+
+ virtual lldb_private::ObjectFile *
+ GetObjectFile (const lldb_private::FileSpec *file);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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:
+
+ struct Object
+ {
+ Object();
+
+ void
+ Clear();
+
+ uint32_t
+ Extract (const lldb_private::DataExtractor& data, uint32_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
+ uint32_t ar_file_offset; // file offset in bytes from the beginning of the file of the object data
+ uint32_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 lldb::SharedPtr<Archive>::Type 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);
+
+ static Archive::shared_ptr
+ ParseAndCacheArchiveForFile (const lldb_private::FileSpec &file,
+ const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &mod_time,
+ lldb_private::DataExtractor &data);
+
+ Archive (const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &mod_time);
+
+ ~Archive ();
+
+ size_t
+ ParseObjects (lldb_private::DataExtractor &data);
+
+ Object *
+ FindObject (const lldb_private::ConstString &object_name);
+
+ const lldb_private::TimeValue &
+ GetModificationTime()
+ {
+ return m_time;
+ }
+
+ const lldb_private::ArchSpec &
+ GetArchitecture ()
+ {
+ return m_arch;
+ }
+
+ protected:
+
+ //----------------------------------------------------------------------
+ // Member Variables
+ //----------------------------------------------------------------------
+ lldb_private::ArchSpec m_arch;
+ lldb_private::TimeValue m_time;
+ Object::collection m_objects;
+ lldb_private::UniqueCStringMap<uint32_t> m_object_name_to_index_map;
+ };
+
+ void
+ SetArchive (Archive::shared_ptr &archive_sp);
+
+ Archive::shared_ptr m_archive_sp;
+};
+
+#endif // liblldb_ObjectContainerBSDArchive_h_
diff --git a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
new file mode 100644
index 00000000000..015e498a7cc
--- /dev/null
+++ b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
@@ -0,0 +1,259 @@
+//===-- ObjectContainerUniversalMachO.cpp -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectContainerUniversalMachO.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+void
+ObjectContainerUniversalMachO::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+ObjectContainerUniversalMachO::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+ObjectContainerUniversalMachO::GetPluginNameStatic()
+{
+ return "object-container.mach-o";
+}
+
+const char *
+ObjectContainerUniversalMachO::GetPluginDescriptionStatic()
+{
+ return "Universal mach-o object container reader.";
+}
+
+
+ObjectContainer *
+ObjectContainerUniversalMachO::CreateInstance
+(
+ Module* module,
+ DataBufferSP& dataSP,
+ const FileSpec *file,
+ addr_t offset,
+ addr_t length
+)
+{
+ if (ObjectContainerUniversalMachO::MagicBytesMatch(dataSP))
+ {
+ std::auto_ptr<ObjectContainerUniversalMachO> container_ap(new ObjectContainerUniversalMachO (module, dataSP, file, offset, length));
+ if (container_ap->ParseHeader())
+ {
+ return container_ap.release();
+ }
+ }
+ return NULL;
+}
+
+
+
+bool
+ObjectContainerUniversalMachO::MagicBytesMatch (DataBufferSP& dataSP)
+{
+ DataExtractor data(dataSP, eByteOrderHost, 4);
+ uint32_t offset = 0;
+ uint32_t magic = data.GetU32(&offset);
+ return magic == FAT_MAGIC || magic == FAT_CIGAM;
+}
+
+ObjectContainerUniversalMachO::ObjectContainerUniversalMachO
+(
+ Module* module,
+ DataBufferSP& dataSP,
+ const FileSpec *file,
+ addr_t offset,
+ addr_t length
+) :
+ ObjectContainer (module, file, offset, length, dataSP),
+ m_header(),
+ m_fat_archs()
+{
+ memset(&m_header, 0, sizeof(m_header));
+}
+
+
+ObjectContainerUniversalMachO::~ObjectContainerUniversalMachO()
+{
+}
+
+bool
+ObjectContainerUniversalMachO::ParseHeader ()
+{
+ // Store the file offset for this universal file as we could have a universal .o file
+ // in a BSD archive, or be contained in another kind of object.
+ uint32_t offset = 0;
+ // Universal mach-o files always have their headers in big endian.
+ m_data.SetByteOrder (eByteOrderBig);
+ m_header.magic = m_data.GetU32(&offset);
+
+ if (m_header.magic == FAT_MAGIC)
+ {
+ m_data.SetAddressByteSize(4);
+
+ m_header.nfat_arch = m_data.GetU32(&offset);
+
+ const size_t nfat_arch_size = sizeof(fat_arch_t) * m_header.nfat_arch;
+ // See if the current data we have is enough for all of the fat headers?
+ if (!m_data.ValidOffsetForDataOfSize(offset, nfat_arch_size))
+ {
+ // The fat headers are larger than the number of bytes we have been
+ // given when this class was constructed. We will read the exact number
+ // of bytes that we need.
+ DataBufferSP data_sp(m_file.ReadFileContents(m_offset, nfat_arch_size + sizeof(fat_header_t)));
+ m_data.SetData (data_sp);
+ }
+
+ // Now we should have enough data for all of the fat headers, so lets index
+ // them so we know how many architectures that this univeral binary contains.
+ uint32_t arch_idx = 0;
+ for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
+ {
+ if (m_data.ValidOffsetForDataOfSize(offset, sizeof(fat_arch_t)))
+ {
+ fat_arch_t arch;
+ if (m_data.GetU32(&offset, &arch, sizeof(fat_arch_t)/sizeof(uint32_t)))
+ {
+ m_fat_archs.push_back(arch);
+ }
+ }
+ }
+ // Now that we have indexed the universal headers, we no longer need any cached data.
+ m_data.Clear();
+
+ return true;
+ }
+ else
+ {
+ memset(&m_header, 0, sizeof(m_header));
+ }
+
+ return false;
+}
+
+void
+ObjectContainerUniversalMachO::Dump (Stream *s) const
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ const size_t num_archs = GetNumArchitectures();
+ const size_t num_objects = GetNumObjects();
+ s->Printf("ObjectContainerUniversalMachO, num_archs = %u, num_objects = %u", 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", arch.AsCString());
+ }
+ for (i=0; i<num_objects; i++)
+ {
+ s->Indent();
+ s->Printf("object[%u] = %s\n", GetObjectNameAtIndex (i));
+ }
+ s->IndentLess();
+ s->EOL();
+}
+
+size_t
+ObjectContainerUniversalMachO::GetNumArchitectures () const
+{
+ return m_header.nfat_arch;
+}
+
+bool
+ObjectContainerUniversalMachO::GetArchitectureAtIndex (uint32_t idx, ArchSpec& arch) const
+{
+ if (idx < m_header.nfat_arch)
+ {
+ arch.SetArch(m_fat_archs[idx].cputype, m_fat_archs[idx].cpusubtype);
+ return true;
+ }
+ return false;
+}
+
+ObjectFile *
+ObjectContainerUniversalMachO::GetObjectFile (const FileSpec *file)
+{
+ uint32_t arch_idx = 0;
+ const ArchSpec arch = m_module->GetArchitecture();
+ ArchSpec curr_arch;
+ for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
+ {
+ if (GetArchitectureAtIndex (arch_idx, curr_arch))
+ {
+ if (arch == curr_arch)
+ {
+ return ObjectFile::FindPlugin (m_module, file, m_offset + m_fat_archs[arch_idx].offset, m_fat_archs[arch_idx].size);
+ }
+ }
+ }
+ return NULL;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ObjectContainerUniversalMachO::GetPluginName()
+{
+ return "ObjectContainerUniversalMachO";
+}
+
+const char *
+ObjectContainerUniversalMachO::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectContainerUniversalMachO::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ObjectContainerUniversalMachO::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ObjectContainerUniversalMachO::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ObjectContainerUniversalMachO::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
+
diff --git a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
new file mode 100644
index 00000000000..8a7f975bc67
--- /dev/null
+++ b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
@@ -0,0 +1,103 @@
+//===-- ObjectContainerUniversalMachO.h -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ObjectContainerUniversalMachO_h_
+#define liblldb_ObjectContainerUniversalMachO_h_
+
+#include <mach-o/fat.h>
+
+#include "lldb/Symbol/ObjectContainer.h"
+#include "lldb/Core/FileSpec.h"
+
+class ObjectContainerUniversalMachO :
+ public lldb_private::ObjectContainer
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectContainer *
+ CreateInstance (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec *file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ static bool
+ MagicBytesMatch (lldb::DataBufferSP& dataSP);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ ObjectContainerUniversalMachO (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec *file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ virtual
+ ~ObjectContainerUniversalMachO();
+
+ virtual bool
+ ParseHeader ();
+
+ virtual void
+ Dump (lldb_private::Stream *s) const;
+
+ virtual size_t
+ GetNumArchitectures () const;
+
+ virtual bool
+ GetArchitectureAtIndex (uint32_t cpu_idx, lldb_private::ArchSpec& arch) const;
+
+ virtual lldb_private::ObjectFile *
+ GetObjectFile (const lldb_private::FileSpec *file);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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:
+ typedef struct fat_header fat_header_t;
+ typedef struct fat_arch fat_arch_t;
+ fat_header_t m_header;
+ std::vector<fat_arch_t> m_fat_archs;
+};
+
+#endif // liblldb_ObjectContainerUniversalMachO_h_
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
new file mode 100644
index 00000000000..b34dd3db289
--- /dev/null
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -0,0 +1,929 @@
+//===-- 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 <mach/machine.h>
+#include <assert.h>
+
+#include <algorithm>
+
+#include <stdint.h>
+#include "elf.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#define CASE_AND_STREAM(s, def, width) case def: s->Printf("%-*s", width, #def); break;
+
+static uint32_t ELFMachineToMachCPU(Elf32_Half machine);
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+
+#include <mach-o/nlist.h>
+#include <mach-o/stab.h>
+
+
+void
+ObjectFileELF::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+ObjectFileELF::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+ObjectFileELF::GetPluginNameStatic()
+{
+ return "object-file.elf32";
+}
+
+const char *
+ObjectFileELF::GetPluginDescriptionStatic()
+{
+ return "ELF object file reader (32-bit).";
+}
+
+
+ObjectFile *
+ObjectFileELF::CreateInstance (Module* module, DataBufferSP& dataSP, const FileSpec* file, addr_t offset, addr_t length)
+{
+ if (ObjectFileELF::MagicBytesMatch(dataSP))
+ {
+ std::auto_ptr<ObjectFile> objfile_ap(new ObjectFileELF (module, dataSP, file, offset, length));
+ if (objfile_ap.get() && objfile_ap->ParseHeader())
+ return objfile_ap.release();
+ }
+ return NULL;
+}
+
+bool
+ObjectFileELF::MagicBytesMatch (DataBufferSP& dataSP)
+{
+ DataExtractor data(dataSP, eByteOrderHost, 4);
+ const uint8_t* magic = data.PeekData(0, 4);
+ if (magic != NULL)
+ {
+ return magic[EI_MAG0] == 0x7f
+ && magic[EI_MAG1] == 'E'
+ && magic[EI_MAG2] == 'L'
+ && magic[EI_MAG3] == 'F';
+ }
+ return false;
+}
+
+
+ObjectFileELF::ObjectFileELF(Module* module, DataBufferSP& dataSP, const FileSpec* file, addr_t offset, addr_t length) :
+ ObjectFile (module, file, offset, length, dataSP),
+ m_header(),
+ m_program_headers(),
+ m_section_headers(),
+ m_sections_ap(),
+ m_symtab_ap(),
+ m_shstr_data()
+{
+ if (file)
+ m_file = *file;
+ ::bzero (&m_header, sizeof(m_header));
+}
+
+
+ObjectFileELF::~ObjectFileELF()
+{
+}
+
+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;
+}
+
+size_t
+ObjectFileELF::GetAddressByteSize () const
+{
+ return m_data.GetAddressByteSize();
+}
+
+bool
+ObjectFileELF::ParseHeader ()
+{
+ m_data.SetAddressByteSize(4);
+ uint32_t offset = GetOffset();
+ if (m_data.GetU8(&offset, m_header.e_ident, EI_NIDENT) == NULL)
+ return false;
+
+ m_data.SetByteOrder(GetByteOrder());
+
+ // Read e_type and e_machine
+ if (m_data.GetU16(&offset, &m_header.e_type, 2) == NULL)
+ return false;
+
+ // read e_version, e_entry, e_phoff, e_shoff, e_flags
+ if (m_data.GetU32(&offset, &m_header.e_version, 5) == NULL)
+ return false;
+
+ // Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx
+ if (m_data.GetU16(&offset, &m_header.e_ehsize, 6) == NULL)
+ return false;
+
+ return true;
+}
+
+bool
+ObjectFileELF::GetUUID (UUID* uuid)
+{
+ return false;
+}
+
+uint32_t
+ObjectFileELF::GetDependentModules(FileSpecList& files)
+{
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// ParseProgramHeaders
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseProgramHeaders()
+{
+ // We have already parsed the program headers
+ if (!m_program_headers.empty())
+ return m_program_headers.size();
+
+ uint32_t offset = 0;
+ if (m_header.e_phnum > 0)
+ {
+ m_program_headers.resize(m_header.e_phnum);
+
+ if (m_program_headers.size() != m_header.e_phnum)
+ return 0;
+
+ const size_t byte_size = m_header.e_phnum * m_header.e_phentsize;
+ DataBufferSP buffer_sp(m_file.ReadFileContents(m_offset + m_header.e_phoff, byte_size));
+
+ if (buffer_sp.get() == NULL || buffer_sp->GetByteSize() != byte_size)
+ return 0;
+
+ DataExtractor data(buffer_sp, m_data.GetByteOrder(), m_data.GetAddressByteSize());
+
+ uint32_t idx;
+ for (idx = 0; idx < m_header.e_phnum; ++idx)
+ {
+ if (data.GetU32(&offset, &m_program_headers[idx].p_type, 8) == NULL)
+ return 0;
+ }
+ if (idx < m_program_headers.size())
+ m_program_headers.resize(idx);
+ }
+
+ return m_program_headers.size();
+}
+
+
+//----------------------------------------------------------------------
+// ParseSectionHeaders
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseSectionHeaders()
+{
+ // We have already parsed the section headers
+ if (!m_section_headers.empty())
+ return m_section_headers.size();
+
+ if (m_header.e_shnum > 0)
+ {
+ uint32_t offset = 0;
+
+ m_section_headers.resize(m_header.e_shnum);
+
+ if (m_section_headers.size() != m_header.e_shnum)
+ return 0;
+
+ const size_t byte_size = m_header.e_shnum * m_header.e_shentsize;
+ DataBufferSP buffer_sp(m_file.ReadFileContents(m_offset + m_header.e_shoff, byte_size));
+
+ if (buffer_sp.get() == NULL || buffer_sp->GetByteSize() != byte_size)
+ return 0;
+
+ DataExtractor data(buffer_sp, m_data.GetByteOrder(), m_data.GetAddressByteSize());
+
+ uint32_t idx;
+ for (idx = 0; idx < m_header.e_shnum; ++idx)
+ {
+ if (data.GetU32(&offset, &m_section_headers[idx].sh_name, 10) == NULL)
+ break;
+ }
+ if (idx < m_section_headers.size())
+ m_section_headers.resize(idx);
+ }
+
+ return m_section_headers.size();
+}
+
+size_t
+ObjectFileELF::GetSectionHeaderStringTable()
+{
+ if (m_shstr_data.GetByteSize() == 0)
+ {
+ if (m_header.e_shstrndx && m_header.e_shstrndx < m_section_headers.size())
+ {
+ const size_t byte_size = m_section_headers[m_header.e_shstrndx].sh_size;
+ DataBufferSP buffer_sp(m_file.ReadFileContents(m_offset + m_section_headers[m_header.e_shstrndx].sh_offset, byte_size));
+
+ if (buffer_sp.get() == NULL || buffer_sp->GetByteSize() != byte_size)
+ return 0;
+
+ m_shstr_data.SetData(buffer_sp);
+ }
+ }
+ return m_shstr_data.GetByteSize();
+}
+
+uint32_t
+ObjectFileELF::GetSectionIndexByName(const char *name)
+{
+ if (ParseSectionHeaders() && GetSectionHeaderStringTable())
+ {
+ uint32_t offset = 1; // Skip leading NULL string at offset 0;
+ while (m_shstr_data.ValidOffset(offset))
+ {
+ uint32_t sh_name = offset; // Save offset in case we find a match
+ const char* sectionHeaderName = m_shstr_data.GetCStr(&offset);
+ if (sectionHeaderName)
+ {
+ if (strcmp(name, sectionHeaderName) == 0)
+ {
+ SectionHeaderCollIter pos;
+ for (pos = m_section_headers.begin(); pos != m_section_headers.end(); ++pos)
+ {
+ if ( (*pos).sh_name == sh_name )
+ {
+ // section indexes are 1 based
+ return std::distance(m_section_headers.begin(), pos) + 1;
+ }
+ }
+ return UINT32_MAX;
+ }
+ }
+ else
+ {
+ return UINT32_MAX;
+ }
+ }
+ }
+
+ return UINT32_MAX;
+}
+
+SectionList *
+ObjectFileELF::GetSectionList()
+{
+ if (m_sections_ap.get() == NULL)
+ {
+ m_sections_ap.reset(new SectionList());
+ if (ParseSectionHeaders() && GetSectionHeaderStringTable())
+ {
+ uint32_t sh_idx = 0;
+ const size_t num_sections = m_section_headers.size();
+ for (sh_idx = 0; sh_idx < num_sections; ++sh_idx)
+ {
+ ConstString section_name(m_shstr_data.PeekCStr(m_section_headers[sh_idx].sh_name));
+ uint64_t section_file_size = m_section_headers[sh_idx].sh_type == SHT_NOBITS ? 0 : m_section_headers[sh_idx].sh_size;
+ SectionSP section_sp(new Section(NULL, // Parent section
+ GetModule(), // Module to which this section belongs
+ sh_idx + 1, // Section ID is the 1 based
+ section_name, // Name of this section
+ eSectionTypeOther, // TODO: fill this in appropriately for ELF...
+ m_section_headers[sh_idx].sh_addr, // File VM address
+ m_section_headers[sh_idx].sh_size, // VM size in bytes of this section
+ m_section_headers[sh_idx].sh_offset, // Offset to the data for this section in the file
+ section_file_size, // Size in bytes of this section as found in the the file
+ m_section_headers[sh_idx].sh_flags)); // Flags for this section
+ if (section_sp.get())
+ m_sections_ap->AddSection(section_sp);
+
+ }
+ }
+ }
+ return m_sections_ap.get();
+}
+
+static void
+ParseSymbols (Symtab *symtab, SectionList *section_list, const Elf32_Shdr &symtab_shdr, const DataExtractor& symtab_data, const DataExtractor& strtab_data)
+{
+ assert (sizeof(Elf32_Sym) == symtab_shdr.sh_entsize);
+ const uint32_t num_symbols = symtab_data.GetByteSize() / sizeof(Elf32_Sym);
+ uint32_t offset = 0;
+ Elf32_Sym symbol;
+ uint32_t i;
+ 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");
+
+ for (i=0; i<num_symbols; ++i)
+ {
+ // if (symtab_data.GetU32(&offset, &symbol.st_name, 3) == 0)
+ // break;
+
+ if (!symtab_data.ValidOffsetForDataOfSize(offset, sizeof(Elf32_Sym)))
+ break;
+
+ symbol.st_name = symtab_data.GetU32 (&offset);
+ symbol.st_value = symtab_data.GetU32 (&offset);
+ symbol.st_size = symtab_data.GetU32 (&offset);
+ symbol.st_info = symtab_data.GetU8 (&offset);
+ symbol.st_other = symtab_data.GetU8 (&offset);
+ symbol.st_shndx = symtab_data.GetU16 (&offset);
+
+ Section * symbol_section = NULL;
+ SymbolType symbol_type = eSymbolTypeInvalid;
+
+ switch (symbol.st_shndx)
+ {
+ case SHN_ABS:
+ symbol_type = eSymbolTypeAbsolute;
+ break;
+ case SHN_UNDEF:
+ symbol_type = eSymbolTypeUndefined;
+ break;
+ default:
+ symbol_section = section_list->GetSectionAtIndex (symbol.st_shndx).get();
+ break;
+ }
+
+ switch (ELF32_ST_BIND (symbol.st_info))
+ {
+ 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 == eSymbolTypeObjectFile;
+ break;
+ }
+
+ if (symbol_type == eSymbolTypeInvalid)
+ {
+ if (symbol_section)
+ {
+ const ConstString &sect_name = symbol_section->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;
+ }
+ }
+ }
+
+ uint64_t symbol_value = symbol.st_value;
+ if (symbol_section != NULL)
+ symbol_value -= symbol_section->GetFileAddress();
+ const char *symbol_name = strtab_data.PeekCStr(symbol.st_name);
+
+ Symbol dc_symbol(i, // ID is the original symbol table index
+ symbol_name, // symbol name
+ false, // Is the symbol name mangled?
+ symbol_type, // type of this symbol
+ ELF32_ST_BIND (symbol.st_info) == STB_GLOBAL, // Is this globally visible?
+ false, // Is this symbol debug info?
+ false, // Is this symbol a trampoline?
+ false, // Is this symbol artificial?
+ symbol_section, // section pointer if symbol_value is an offset within a section, else NULL
+ symbol_value, // offset from section if section is non-NULL, else the value for this symbol
+ symbol.st_size, // size in bytes of this symbol
+ symbol.st_other << 8 | symbol.st_info); // symbol flags
+ symtab->AddSymbol(dc_symbol);
+ }
+}
+
+
+Symtab *
+ObjectFileELF::GetSymtab()
+{
+ if (m_symtab_ap.get() == NULL)
+ {
+ m_symtab_ap.reset(new Symtab(this));
+
+ if (ParseSectionHeaders() && GetSectionHeaderStringTable())
+ {
+ uint32_t symtab_idx = UINT32_MAX;
+ uint32_t dynsym_idx = UINT32_MAX;
+ uint32_t sh_idx = 0;
+ const size_t num_sections = m_section_headers.size();
+ for (sh_idx = 0; sh_idx < num_sections; ++sh_idx)
+ {
+ if (m_section_headers[sh_idx].sh_type == SHT_SYMTAB)
+ {
+ symtab_idx = sh_idx;
+ break;
+ }
+ if (m_section_headers[sh_idx].sh_type == SHT_DYNSYM)
+ {
+ dynsym_idx = sh_idx;
+ }
+ }
+
+ SectionList *section_list = NULL;
+ static ConstString g_symtab(".symtab");
+ static ConstString g_strtab(".strtab");
+ static ConstString g_dynsym(".dynsym");
+ static ConstString g_dynstr(".dynstr");
+ // Check if we found a full symbol table?
+ if (symtab_idx < num_sections)
+ {
+ section_list = GetSectionList();
+ if (section_list)
+ {
+ Section *symtab_section = section_list->FindSectionByName(g_symtab).get();
+ Section *strtab_section = section_list->FindSectionByName(g_strtab).get();
+ if (symtab_section && strtab_section)
+ {
+ DataExtractor symtab_data;
+ DataExtractor strtab_data;
+ if (symtab_section->ReadSectionDataFromObjectFile (this, symtab_data) > 0 &&
+ strtab_section->ReadSectionDataFromObjectFile (this, strtab_data) > 0)
+ {
+ ParseSymbols (m_symtab_ap.get(), section_list, m_section_headers[symtab_idx], symtab_data, strtab_data);
+ }
+ }
+ }
+ }
+ // Check if we found a reduced symbol table that gets used for dynamic linking?
+ else if (dynsym_idx < num_sections)
+ {
+ section_list = GetSectionList();
+ if (section_list)
+ {
+ Section *dynsym_section = section_list->FindSectionByName(g_dynsym).get();
+ Section *dynstr_section = section_list->FindSectionByName(g_dynstr).get();
+ if (dynsym_section && dynstr_section)
+ {
+ DataExtractor dynsym_data;
+ DataExtractor dynstr_data;
+ if (dynsym_section->ReadSectionDataFromObjectFile (this, dynsym_data) > 0 &&
+ dynstr_section->ReadSectionDataFromObjectFile (this, dynstr_data) > 0)
+ {
+ ParseSymbols (m_symtab_ap.get(), section_list, m_section_headers[dynsym_idx], dynsym_data, dynstr_data);
+ }
+ }
+ }
+ }
+ }
+ }
+ return m_symtab_ap.get();
+}
+
+//
+////----------------------------------------------------------------------
+//// GetNListSymtab
+////----------------------------------------------------------------------
+//bool
+//ELF32RuntimeFileParser::GetNListSymtab(BinaryDataRef& stabs_data, BinaryDataRef& stabstr_data, bool locals_only, uint32_t& value_size)
+//{
+// value_size = 4; // Size in bytes of the nlist n_value member
+// return GetSectionInfo(GetSectionIndexByName(".stab"), NULL, NULL, NULL, NULL, NULL, NULL, &stabs_data, NULL) &&
+// GetSectionInfo(GetSectionIndexByName(".stabstr"), NULL, NULL, NULL, NULL, NULL, NULL, &stabstr_data, NULL);
+//}
+//
+//===----------------------------------------------------------------------===//
+// 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);
+ Symtab *symtab = GetSymtab();
+ if (symtab)
+ symtab->Dump(s, NULL);
+ s->EOL();
+}
+
+//----------------------------------------------------------------------
+// DumpELFHeader
+//
+// Dump the ELF header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFHeader(Stream *s, const Elf32_Ehdr& 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.8x\n", header.e_entry);
+ s->Printf("e_phoff = 0x%8.8x\n", header.e_phoff);
+ s->Printf("e_shoff = 0x%8.8x\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, uint16_t 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, uint16_t 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 Elf32_Phdr& ph)
+{
+ DumpELFProgramHeader_p_type(s, ph.p_type);
+ s->Printf(" %8.8x %8.8x %8.8x %8.8x %8.8x %8.8x (", ph.p_offset, ph.p_vaddr, ph.p_paddr, ph.p_filesz, ph.p_memsz, ph.p_flags);
+ DumpELFProgramHeader_p_flags(s, ph.p_flags);
+ s->Printf(") %8.8x", 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, Elf32_Word p_type)
+{
+ const int kStrWidth = 10;
+ 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);
+ 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, Elf32_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;
+ ProgramHeaderCollConstIter pos;
+
+ for (pos = m_program_headers.begin(); pos != m_program_headers.end(); ++pos, ++idx)
+ {
+ s->Printf ("[%2u] ", idx);
+ ObjectFileELF::DumpELFProgramHeader(s, *pos);
+ s->EOL();
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DumpELFSectionHeader
+//
+// Dump a single ELF section header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeader(Stream *s, const Elf32_Shdr& sh)
+{
+ s->Printf ("%8.8x ", sh.sh_name);
+ DumpELFSectionHeader_sh_type(s, sh.sh_type);
+ s->Printf (" %8.8x (", sh.sh_flags);
+ DumpELFSectionHeader_sh_flags(s, sh.sh_flags);
+ s->Printf (") %8.8x %8.8x %8.8x %8.8x %8.8x %8.8x %8.8x",
+ sh.sh_addr, sh.sh_offset, sh.sh_size, sh.sh_link, sh.sh_info, 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, Elf32_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, Elf32_Word 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() && GetSectionHeaderStringTable())
+ {
+ 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;
+ SectionHeaderCollConstIter pos;
+
+ for (pos = m_section_headers.begin(); pos != m_section_headers.end(); ++pos, ++idx)
+ {
+ s->Printf ("[%2u] ", idx);
+ ObjectFileELF::DumpELFSectionHeader(s, *pos);
+ const char* section_name = m_shstr_data.PeekCStr(pos->sh_name);
+ if (section_name)
+ *s << ' ' << section_name << "\n";
+ }
+ }
+}
+
+static uint32_t
+ELFMachineToMachCPU(Elf32_Half machine)
+{
+ switch (machine)
+ {
+ case EM_SPARC: return CPU_TYPE_SPARC;
+ case EM_386: return CPU_TYPE_I386;
+ case EM_68K: return CPU_TYPE_MC680x0;
+ case EM_88K: return CPU_TYPE_MC88000;
+ case EM_860: return CPU_TYPE_I860;
+ case EM_MIPS: return 8; // commented out in mach/machine.h
+ case EM_PPC: return CPU_TYPE_POWERPC;
+ case EM_PPC64: return CPU_TYPE_POWERPC64;
+ case EM_ARM: return 12; // commented out in mach/machine.h
+ }
+ return 0;
+}
+
+bool
+ObjectFileELF::GetTargetTriple (ConstString &target_triple)
+{
+ static ConstString g_target_triple;
+
+ if (g_target_triple)
+ {
+ target_triple = g_target_triple;
+ }
+ else
+ {
+ std::string triple;
+ switch (m_header.e_machine)
+ {
+ case EM_SPARC: triple.assign("sparc-"); break;
+ case EM_386: triple.assign("i386-"); break;
+ case EM_68K: triple.assign("68k-"); break;
+ case EM_88K: triple.assign("88k-"); break;
+ case EM_860: triple.assign("i860-"); break;
+ case EM_MIPS: triple.assign("mips-"); break;
+ case EM_PPC: triple.assign("powerpc-"); break;
+ case EM_PPC64: triple.assign("powerpc64-"); break;
+ case EM_ARM: triple.assign("arm-"); break;
+ }
+ // TODO: determine if there is a vendor in the ELF? Default to "apple" for now
+ triple += "apple-";
+ // TODO: determine if there is an OS in the ELF? Default to "darwin" for now
+ triple += "darwin10";
+ g_target_triple.SetCString(triple.c_str());
+ target_triple = g_target_triple;
+ }
+ return !target_triple.IsEmpty();
+}
+
+
+//bool
+//ELF32RuntimeFileParser::GetArch(ArchSpec &arch) const
+//{
+// arch.SetCPUType(ELFMachineToMachCPU(m_header.e_machine));
+// arch.SetCPUSubtype(ArchSpec::eAny);
+// return true;
+//}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ObjectFileELF::GetPluginName()
+{
+ return "ObjectFileELF";
+}
+
+const char *
+ObjectFileELF::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectFileELF::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ObjectFileELF::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ObjectFileELF::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ObjectFileELF::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
+
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
new file mode 100644
index 00000000000..5d5778c78fb
--- /dev/null
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -0,0 +1,197 @@
+//===-- 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/Core/FileSpec.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#include "elf.h"
+
+//----------------------------------------------------------------------
+// This class needs to be hidden as eventually belongs in a plugin that
+// will export the ObjectFile protocol
+//----------------------------------------------------------------------
+class ObjectFileELF :
+ public lldb_private::ObjectFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectFile *
+ CreateInstance (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec* file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+ static bool
+ MagicBytesMatch (lldb::DataBufferSP& dataSP);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ ObjectFileELF (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec* file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ virtual
+ ~ObjectFileELF();
+
+ virtual bool
+ ParseHeader ();
+
+ virtual lldb::ByteOrder
+ GetByteOrder () const;
+
+ virtual size_t
+ GetAddressByteSize () const;
+
+ virtual lldb_private::Symtab *
+ GetSymtab();
+
+ virtual lldb_private::SectionList *
+ GetSectionList();
+
+ virtual void
+ Dump (lldb_private::Stream *s);
+
+ virtual bool
+ GetTargetTriple (lldb_private::ConstString &target_triple);
+
+ virtual bool
+ GetUUID (lldb_private::UUID* uuid);
+
+ virtual uint32_t
+ GetDependentModules(lldb_private::FileSpecList& files);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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:
+ typedef std::vector<Elf32_Phdr> ProgramHeaderColl;
+ typedef ProgramHeaderColl::iterator ProgramHeaderCollIter;
+ typedef ProgramHeaderColl::const_iterator ProgramHeaderCollConstIter;
+
+ typedef std::vector<Elf32_Shdr> SectionHeaderColl;
+ typedef SectionHeaderColl::iterator SectionHeaderCollIter;
+ typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter;
+
+ Elf32_Ehdr m_header;
+ ProgramHeaderColl m_program_headers;
+ SectionHeaderColl m_section_headers;
+ mutable std::auto_ptr<lldb_private::SectionList> m_sections_ap;
+ mutable std::auto_ptr<lldb_private::Symtab> m_symtab_ap;
+ lldb_private::DataExtractor m_shstr_data;
+
+ size_t
+ ParseSections ();
+
+ size_t
+ ParseSymtab (bool minimize);
+
+private:
+
+ // ELF header dump routines
+ static void
+ DumpELFHeader (lldb_private::Stream *s,
+ const Elf32_Ehdr& header);
+
+ static void
+ DumpELFHeader_e_ident_EI_DATA (lldb_private::Stream *s,
+ uint16_t ei_data);
+ static void
+ DumpELFHeader_e_type (lldb_private::Stream *s,
+ uint16_t e_type);
+
+ // ELF program header dump routines
+ void
+ DumpELFProgramHeaders (lldb_private::Stream *s);
+
+ static void
+ DumpELFProgramHeader (lldb_private::Stream *s,
+ const Elf32_Phdr& ph);
+
+ static void
+ DumpELFProgramHeader_p_type (lldb_private::Stream *s,
+ Elf32_Word p_type);
+
+ static void
+ DumpELFProgramHeader_p_flags (lldb_private::Stream *s,
+ Elf32_Word p_flags);
+
+ // ELF section header dump routines
+ void
+ DumpELFSectionHeaders (lldb_private::Stream *s);
+
+ static void
+ DumpELFSectionHeader (lldb_private::Stream *s,
+ const Elf32_Shdr& sh);
+
+ static void
+ DumpELFSectionHeader_sh_type (lldb_private::Stream *s,
+ Elf32_Word sh_type);
+
+ static void
+ DumpELFSectionHeader_sh_flags (lldb_private::Stream *s,
+ Elf32_Word sh_flags);
+
+ size_t
+ ParseProgramHeaders ();
+
+ size_t
+ ParseSectionHeaders ();
+
+ size_t
+ GetSectionHeaderStringTable ();
+
+ uint32_t
+ GetSectionIndexByName (const char *name);
+};
+
+#endif // #ifndef liblldb_ObjectFileELF_h_
diff --git a/lldb/source/Plugins/ObjectFile/ELF/elf.h b/lldb/source/Plugins/ObjectFile/ELF/elf.h
new file mode 100644
index 00000000000..9d08119c597
--- /dev/null
+++ b/lldb/source/Plugins/ObjectFile/ELF/elf.h
@@ -0,0 +1,240 @@
+//===-- elf.h ---------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __elf_h__
+#define __elf_h__
+
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf32_Addr;
+typedef uint32_t Elf32_Off;
+
+
+#define EI_NIDENT 16
+
+//----------------------------------------------------------------------
+// ELF Header
+//----------------------------------------------------------------------
+typedef struct Elf32_Ehdr_Tag
+{
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+//----------------------------------------------------------------------
+// e_type
+//
+// This member identifies the object file type.
+//----------------------------------------------------------------------
+#define ET_NONE 0 // No file type
+#define ET_REL 1 // Relocatable file
+#define ET_EXEC 2 // Executable file
+#define ET_DYN 3 // Shared object file
+#define ET_CORE 4 // Core file
+#define ET_LOPROC 0xff00 // Processor-specific
+#define ET_HIPROC 0xffff // Processor-specific
+
+//----------------------------------------------------------------------
+// e_machine
+//
+// Machine Type
+//----------------------------------------------------------------------
+#define EM_NONE 0 // No machine
+#define EM_M32 1 // AT&T WE 32100
+#define EM_SPARC 2 // SPARC
+#define EM_386 3 // Intel 80386
+#define EM_68K 4 // Motorola 68000
+#define EM_88K 5 // Motorola 88000
+#define EM_860 7 // Intel 80860
+#define EM_MIPS 8 // MIPS RS3000
+#define EM_PPC 20 // PowerPC
+#define EM_PPC64 21 // PowerPC64
+#define EM_ARM 40 // ARM
+
+
+//----------------------------------------------------------------------
+// e_ident indexes
+//----------------------------------------------------------------------
+#define EI_MAG0 0 // File identification
+#define EI_MAG1 1 // File identification
+#define EI_MAG2 2 // File identification
+#define EI_MAG3 3 // File identification
+#define EI_CLASS 4 // File class
+#define EI_DATA 5 // Data encoding
+#define EI_VERSION 6 // File version
+#define EI_PAD 7 // Start of padding bytes
+
+
+//----------------------------------------------------------------------
+// EI_DATA definitions
+//----------------------------------------------------------------------
+#define ELFDATANONE 0 // Invalid data encoding
+#define ELFDATA2LSB 1 // Little Endian
+#define ELFDATA2MSB 2 // Big Endian
+
+//----------------------------------------------------------------------
+// Section Header
+//----------------------------------------------------------------------
+typedef struct Elf32_Shdr_Tag
+{
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+//----------------------------------------------------------------------
+// Section Types (sh_type)
+//----------------------------------------------------------------------
+#define SHT_NULL 0
+#define SHT_PROGBITS 1
+#define SHT_SYMTAB 2
+#define SHT_STRTAB 3
+#define SHT_RELA 4
+#define SHT_HASH 5
+#define SHT_DYNAMIC 6
+#define SHT_NOTE 7
+#define SHT_NOBITS 8
+#define SHT_REL 9
+#define SHT_SHLIB 10
+#define SHT_DYNSYM 11
+#define SHT_LOPROC 0x70000000
+#define SHT_HIPROC 0x7fffffff
+#define SHT_LOUSER 0x80000000
+#define SHT_HIUSER 0xffffffff
+
+//----------------------------------------------------------------------
+// Special Section Indexes
+//----------------------------------------------------------------------
+#define SHN_UNDEF 0
+#define SHN_LORESERVE 0xff00
+#define SHN_LOPROC 0xff00
+#define SHN_HIPROC 0xff1f
+#define SHN_ABS 0xfff1
+#define SHN_COMMON 0xfff2
+#define SHN_HIRESERVE 0xffff
+
+//----------------------------------------------------------------------
+// Section Attribute Flags (sh_flags)
+//----------------------------------------------------------------------
+#define SHF_WRITE 0x1
+#define SHF_ALLOC 0x2
+#define SHF_EXECINSTR 0x4
+#define SHF_MASKPROC 0xf0000000
+
+
+//----------------------------------------------------------------------
+// Symbol Table Entry Header
+//----------------------------------------------------------------------
+typedef struct Elf32_Sym_Tag
+{
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+} Elf32_Sym;
+
+
+#define ELF32_ST_BIND(i) ((i)>>4)
+#define ELF32_ST_TYPE(i) ((i)&0xf)
+#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
+
+// ST_BIND
+#define STB_LOCAL 0
+#define STB_GLOBAL 1
+#define STB_WEAK 2
+#define STB_LOPROC 13
+#define STB_HIPROC 15
+
+// ST_TYPE
+#define STT_NOTYPE 0
+#define STT_OBJECT 1
+#define STT_FUNC 2
+#define STT_SECTION 3
+#define STT_FILE 4
+#define STT_LOPROC 13
+#define STT_HIPROC 15
+
+
+//----------------------------------------------------------------------
+// Relocation Entries
+//----------------------------------------------------------------------
+typedef struct Elf32_Rel_Tag
+{
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+} Elf32_Rel;
+
+typedef struct Elf32_Rela_Tag
+{
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+ Elf32_Sword r_addend;
+} Elf32_Rela;
+
+#define ELF32_R_SYM(i) ((i)>>8)
+#define ELF32_R_TYPE(i) ((unsignedchar)(i))
+#define ELF32_R_INFO(s,t) (((s)<<8)+(unsignedchar)(t))
+
+
+//----------------------------------------------------------------------
+// Program Headers
+//----------------------------------------------------------------------
+typedef struct Elf32_Phdr_Tag
+{
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+//----------------------------------------------------------------------
+// Program Header Type (p_type)
+//----------------------------------------------------------------------
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_LOPROC 0x70000000
+#define PT_HIPROC 0x7fffffff
+
+#define PF_X (1 << 0) // executable
+#define PF_W (1 << 1) // writable
+#define PF_R (1 << 2) // readable
+
+
+#endif // __elf_h__
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
new file mode 100644
index 00000000000..682a116d213
--- /dev/null
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -0,0 +1,1311 @@
+//===-- ObjectFileMachO.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectFileMachO.h"
+
+#include <mach-o/nlist.h>
+#include <mach-o/stab.h>
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#ifndef S_DTRACE_DOF
+// section contains DTrace Object Format
+#define S_DTRACE_DOF 0xf
+#endif
+
+#ifndef S_LAZY_DYLIB_SYMBOL_POINTERS
+// section with only lazy symbol pointers to lazy loaded dylibs
+#define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+void
+ObjectFileMachO::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+ObjectFileMachO::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+ObjectFileMachO::GetPluginNameStatic()
+{
+ return "object-file.mach-o";
+}
+
+const char *
+ObjectFileMachO::GetPluginDescriptionStatic()
+{
+ return "Mach-o object file reader (32 and 64 bit)";
+}
+
+
+ObjectFile *
+ObjectFileMachO::CreateInstance (Module* module, DataBufferSP& dataSP, const FileSpec* file, addr_t offset, addr_t length)
+{
+ if (ObjectFileMachO::MagicBytesMatch(dataSP))
+ {
+ std::auto_ptr<ObjectFile> objfile_ap(new ObjectFileMachO (module, dataSP, file, offset, length));
+ if (objfile_ap.get() && objfile_ap->ParseHeader())
+ return objfile_ap.release();
+ }
+ return NULL;
+}
+
+
+static uint32_t
+MachHeaderSizeFromMagic(uint32_t magic)
+{
+ switch (magic)
+ {
+ case MH_MAGIC:
+ case MH_CIGAM:
+ return sizeof(struct mach_header);
+
+ case MH_MAGIC_64:
+ case MH_CIGAM_64:
+ return sizeof(struct mach_header_64);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+bool
+ObjectFileMachO::MagicBytesMatch (DataBufferSP& dataSP)
+{
+ DataExtractor data(dataSP, eByteOrderHost, 4);
+ uint32_t offset = 0;
+ uint32_t magic = data.GetU32(&offset);
+ return MachHeaderSizeFromMagic(magic) != 0;
+}
+
+
+ObjectFileMachO::ObjectFileMachO(Module* module, DataBufferSP& dataSP, const FileSpec* file, addr_t offset, addr_t length) :
+ ObjectFile(module, file, offset, length, dataSP),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_header(),
+ m_sections_ap(),
+ m_symtab_ap()
+{
+ ::bzero (&m_header, sizeof(m_header));
+ ::bzero (&m_dysymtab, sizeof(m_dysymtab));
+}
+
+
+ObjectFileMachO::~ObjectFileMachO()
+{
+}
+
+
+bool
+ObjectFileMachO::ParseHeader ()
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ bool can_parse = false;
+ uint32_t offset = 0;
+ m_data.SetByteOrder (eByteOrderHost);
+ // Leave magic in the original byte order
+ m_header.magic = m_data.GetU32(&offset);
+ switch (m_header.magic)
+ {
+ case MH_MAGIC:
+ m_data.SetByteOrder (eByteOrderHost);
+ m_data.SetAddressByteSize(4);
+ can_parse = true;
+ break;
+
+ case MH_MAGIC_64:
+ m_data.SetByteOrder (eByteOrderHost);
+ m_data.SetAddressByteSize(8);
+ can_parse = true;
+ break;
+
+ case MH_CIGAM:
+ m_data.SetByteOrder(eByteOrderHost == eByteOrderBig ? eByteOrderLittle : eByteOrderBig);
+ m_data.SetAddressByteSize(4);
+ can_parse = true;
+ break;
+
+ case MH_CIGAM_64:
+ m_data.SetByteOrder(eByteOrderHost == eByteOrderBig ? eByteOrderLittle : eByteOrderBig);
+ m_data.SetAddressByteSize(8);
+ can_parse = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (can_parse)
+ {
+ m_data.GetU32(&offset, &m_header.cputype, 6);
+
+ ArchSpec mach_arch(m_header.cputype, m_header.cpusubtype);
+ if (mach_arch == m_module->GetArchitecture())
+ {
+ // Read in all only the load command data
+ DataBufferSP data_sp(m_file.ReadFileContents(m_offset, m_header.sizeofcmds + MachHeaderSizeFromMagic(m_header.magic)));
+ m_data.SetData (data_sp);
+ return true;
+ }
+ }
+ else
+ {
+ memset(&m_header, 0, sizeof(struct mach_header));
+ }
+ return false;
+}
+
+
+ByteOrder
+ObjectFileMachO::GetByteOrder () const
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ return m_data.GetByteOrder ();
+}
+
+
+size_t
+ObjectFileMachO::GetAddressByteSize () const
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ return m_data.GetAddressByteSize ();
+}
+
+
+Symtab *
+ObjectFileMachO::GetSymtab()
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ if (m_symtab_ap.get() == NULL)
+ {
+ m_symtab_ap.reset(new Symtab(this));
+ ParseSymtab(false);
+ }
+ return m_symtab_ap.get();
+}
+
+
+SectionList *
+ObjectFileMachO::GetSectionList()
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ if (m_sections_ap.get() == NULL)
+ {
+ m_sections_ap.reset(new SectionList());
+ ParseSections();
+ }
+ return m_sections_ap.get();
+}
+
+
+size_t
+ObjectFileMachO::ParseSections ()
+{
+ lldb::user_id_t segID = 0;
+ lldb::user_id_t sectID = 0;
+ struct segment_command_64 load_cmd;
+ uint32_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t i;
+ //bool dump_sections = false;
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const uint32_t load_cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64)
+ {
+ if (m_data.GetU8(&offset, (uint8_t*)load_cmd.segname, 16))
+ {
+ load_cmd.vmaddr = m_data.GetAddress(&offset);
+ load_cmd.vmsize = m_data.GetAddress(&offset);
+ load_cmd.fileoff = m_data.GetAddress(&offset);
+ load_cmd.filesize = m_data.GetAddress(&offset);
+ if (m_data.GetU32(&offset, &load_cmd.maxprot, 4))
+ {
+ // Keep a list of mach segments around in case we need to
+ // get at data that isn't stored in the abstracted Sections.
+ m_mach_segments.push_back (load_cmd);
+
+ ConstString segment_name (load_cmd.segname, std::min<int>(strlen(load_cmd.segname), sizeof(load_cmd.segname)));
+ // Use a segment ID of the segment index shifted left by 8 so they
+ // never conflict with any of the sections.
+ SectionSP segment_sp;
+ if (segment_name)
+ {
+ segment_sp.reset(new Section (NULL,
+ GetModule(), // Module to which this section belongs
+ ++segID << 8, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible
+ segment_name, // Name of this section
+ eSectionTypeContainer, // This section is a container of other sections.
+ load_cmd.vmaddr, // File VM address == addresses as they are found in the object file
+ load_cmd.vmsize, // VM size in bytes of this section
+ load_cmd.fileoff, // Offset to the data for this section in the file
+ load_cmd.filesize, // Size in bytes of this section as found in the the file
+ load_cmd.flags)); // Flags for this section
+
+ m_sections_ap->AddSection(segment_sp);
+ }
+
+ struct section_64 sect64;
+ ::bzero (&sect64, sizeof(sect64));
+ // Push a section into our mach sections for the section at
+ // index zero (NO_SECT)
+ m_mach_sections.push_back(sect64);
+ uint32_t segment_sect_idx;
+ const lldb::user_id_t first_segment_sectID = sectID + 1;
+
+
+ const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8;
+ for (segment_sect_idx=0; segment_sect_idx<load_cmd.nsects; ++segment_sect_idx)
+ {
+ if (m_data.GetU8(&offset, (uint8_t*)sect64.sectname, sizeof(sect64.sectname)) == NULL)
+ break;
+ if (m_data.GetU8(&offset, (uint8_t*)sect64.segname, sizeof(sect64.segname)) == NULL)
+ break;
+ sect64.addr = m_data.GetAddress(&offset);
+ sect64.size = m_data.GetAddress(&offset);
+
+ if (m_data.GetU32(&offset, &sect64.offset, num_u32s) == NULL)
+ break;
+
+ // Keep a list of mach sections around in case we need to
+ // get at data that isn't stored in the abstracted Sections.
+ m_mach_sections.push_back (sect64);
+
+ ConstString section_name (sect64.sectname, std::min<size_t>(strlen(sect64.sectname), sizeof(sect64.sectname)));
+ if (!segment_name)
+ {
+ // We have a segment with no name so we need to conjure up
+ // segments that correspond to the section's segname if there
+ // isn't already such a section. If there is such a section,
+ // we resize the section so that it spans all sections.
+ // We also mark these sections as fake so address matches don't
+ // hit if they land in the gaps between the child sections.
+ segment_name.SetTrimmedCStringWithLength(sect64.segname, sizeof(sect64.segname));
+ segment_sp = m_sections_ap->FindSectionByName (segment_name);
+ if (segment_sp.get())
+ {
+ Section *segment = segment_sp.get();
+ // Grow the section size as needed.
+ const lldb::addr_t sect64_min_addr = sect64.addr;
+ const lldb::addr_t sect64_max_addr = sect64_min_addr + sect64.size;
+ const lldb::addr_t curr_seg_byte_size = segment->GetByteSize();
+ const lldb::addr_t curr_seg_min_addr = segment->GetFileAddress();
+ const lldb::addr_t curr_seg_max_addr = curr_seg_min_addr + curr_seg_byte_size;
+ if (sect64_min_addr >= curr_seg_min_addr)
+ {
+ const lldb::addr_t new_seg_byte_size = sect64_max_addr - curr_seg_min_addr;
+ // Only grow the section size if needed
+ if (new_seg_byte_size > curr_seg_byte_size)
+ segment->SetByteSize (new_seg_byte_size);
+ }
+ else
+ {
+ // We need to change the base address of the segment and
+ // adjust the child section offsets for all existing children.
+ const lldb::addr_t slide_amount = sect64_min_addr - curr_seg_min_addr;
+ segment->Slide(slide_amount, false);
+ segment->GetChildren().Slide (-slide_amount, false);
+ segment->SetByteSize (curr_seg_max_addr - sect64_min_addr);
+ }
+ }
+ else
+ {
+ // Create a fake section for the section's named segment
+ segment_sp.reset(new Section(segment_sp.get(), // Parent section
+ GetModule(), // Module to which this section belongs
+ ++segID << 8, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible
+ segment_name, // Name of this section
+ eSectionTypeContainer, // This section is a container of other sections.
+ sect64.addr, // File VM address == addresses as they are found in the object file
+ sect64.size, // VM size in bytes of this section
+ sect64.offset, // Offset to the data for this section in the file
+ sect64.offset ? sect64.size : 0, // Size in bytes of this section as found in the the file
+ load_cmd.flags)); // Flags for this section
+ segment_sp->SetIsFake(true);
+ m_sections_ap->AddSection(segment_sp);
+ }
+ }
+ assert (segment_sp.get());
+
+ uint32_t mach_sect_type = sect64.flags & SECTION_TYPE;
+ static ConstString g_sect_name_objc_data ("__objc_data");
+ static ConstString g_sect_name_objc_msgrefs ("__objc_msgrefs");
+ static ConstString g_sect_name_objc_selrefs ("__objc_selrefs");
+ static ConstString g_sect_name_objc_classrefs ("__objc_classrefs");
+ static ConstString g_sect_name_objc_superrefs ("__objc_superrefs");
+ static ConstString g_sect_name_objc_const ("__objc_const");
+ static ConstString g_sect_name_objc_classlist ("__objc_classlist");
+ static ConstString g_sect_name_cfstring ("__cfstring");
+ SectionType sect_type = eSectionTypeOther;
+
+ if (section_name == g_sect_name_objc_selrefs)
+ {
+ sect_type = eSectionTypeDataCStringPointers;
+ }
+ else if (section_name == g_sect_name_objc_msgrefs)
+ {
+ sect_type = eSectionTypeDataObjCMessageRefs;
+ }
+ else if (section_name == g_sect_name_objc_data ||
+ section_name == g_sect_name_objc_classrefs ||
+ section_name == g_sect_name_objc_superrefs ||
+ section_name == g_sect_name_objc_const ||
+ section_name == g_sect_name_objc_classlist)
+ {
+ sect_type = eSectionTypeDataPointers;
+ }
+ else if (section_name == g_sect_name_cfstring)
+ {
+ sect_type = eSectionTypeDataObjCCFStrings;
+ }
+
+ if (sect_type == eSectionTypeOther)
+ {
+ switch (mach_sect_type)
+ {
+ // TODO: categorize sections by other flags for regular sections
+ case S_REGULAR:
+
+ sect_type = eSectionTypeOther;
+ break;
+ case S_ZEROFILL: sect_type = eSectionTypeZeroFill; break;
+ case S_CSTRING_LITERALS: sect_type = eSectionTypeDataCString; break; // section with only literal C strings
+ case S_4BYTE_LITERALS: sect_type = eSectionTypeData4; break; // section with only 4 byte literals
+ case S_8BYTE_LITERALS: sect_type = eSectionTypeData8; break; // section with only 8 byte literals
+ case S_LITERAL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only pointers to literals
+ case S_NON_LAZY_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only non-lazy symbol pointers
+ case S_LAZY_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only lazy symbol pointers
+ case S_SYMBOL_STUBS: sect_type = eSectionTypeCode; break; // section with only symbol stubs, byte size of stub in the reserved2 field
+ case S_MOD_INIT_FUNC_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only function pointers for initialization
+ case S_MOD_TERM_FUNC_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only function pointers for termination
+ case S_COALESCED: sect_type = eSectionTypeOther; break;
+ case S_GB_ZEROFILL: sect_type = eSectionTypeZeroFill; break;
+ case S_INTERPOSING: sect_type = eSectionTypeCode; break; // section with only pairs of function pointers for interposing
+ case S_16BYTE_LITERALS: sect_type = eSectionTypeData16; break; // section with only 16 byte literals
+ case S_DTRACE_DOF: sect_type = eSectionTypeDebug; break;
+ case S_LAZY_DYLIB_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break;
+ default: break;
+ }
+ }
+
+ SectionSP section_sp(new Section(segment_sp.get(),
+ GetModule(),
+ ++sectID,
+ section_name,
+ sect_type,
+ sect64.addr - segment_sp->GetFileAddress(),
+ sect64.size,
+ sect64.offset,
+ sect64.offset == 0 ? 0 : sect64.size,
+ sect64.flags));
+ segment_sp->GetChildren().AddSection(section_sp);
+
+ if (segment_sp->IsFake())
+ {
+ segment_sp.reset();
+ segment_name.Clear();
+ }
+ }
+ if (m_header.filetype == MH_DSYM)
+ {
+ if (first_segment_sectID <= sectID)
+ {
+ lldb::user_id_t sect_uid;
+ for (sect_uid = first_segment_sectID; sect_uid <= sectID; ++sect_uid)
+ {
+ SectionSP curr_section_sp(segment_sp->GetChildren().FindSectionByID (sect_uid));
+ SectionSP next_section_sp;
+ if (sect_uid + 1 <= sectID)
+ next_section_sp = segment_sp->GetChildren().FindSectionByID (sect_uid+1);
+
+ if (curr_section_sp.get())
+ {
+ if (curr_section_sp->GetByteSize() == 0)
+ {
+ if (next_section_sp.get() != NULL)
+ curr_section_sp->SetByteSize ( next_section_sp->GetFileAddress() - curr_section_sp->GetFileAddress() );
+ else
+ curr_section_sp->SetByteSize ( load_cmd.vmsize );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (load_cmd.cmd == LC_DYSYMTAB)
+ {
+ m_dysymtab.cmd = load_cmd.cmd;
+ m_dysymtab.cmdsize = load_cmd.cmdsize;
+ m_data.GetU32 (&offset, &m_dysymtab.ilocalsym, (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2);
+ }
+
+ offset = load_cmd_offset + load_cmd.cmdsize;
+ }
+// if (dump_sections)
+// {
+// StreamFile s(stdout);
+// m_sections_ap->Dump(&s, true);
+// }
+ return sectID; // Return the number of sections we registered with the module
+}
+
+class MachSymtabSectionInfo
+{
+public:
+
+ MachSymtabSectionInfo (SectionList *section_list) :
+ m_section_list (section_list),
+ m_section_infos()
+ {
+ // Get the number of sections down to a depth of 1 to include
+ // all segments and their sections, but no other sections that
+ // may be added for debug map or
+ m_section_infos.resize(section_list->GetNumSections(1));
+ }
+
+
+ Section *
+ GetSection (uint8_t n_sect, addr_t file_addr)
+ {
+ if (n_sect == 0)
+ return NULL;
+ if (n_sect < m_section_infos.size())
+ {
+ if (m_section_infos[n_sect].section == NULL)
+ {
+ Section *section = m_section_list->FindSectionByID (n_sect).get();
+ m_section_infos[n_sect].section = section;
+ assert (section != NULL);
+ m_section_infos[n_sect].vm_range.SetBaseAddress (section->GetFileAddress());
+ m_section_infos[n_sect].vm_range.SetByteSize (section->GetByteSize());
+ }
+ if (m_section_infos[n_sect].vm_range.Contains(file_addr))
+ return m_section_infos[n_sect].section;
+ }
+ return m_section_list->FindSectionContainingFileAddress(file_addr).get();
+ }
+
+protected:
+ struct SectionInfo
+ {
+ SectionInfo () :
+ vm_range(),
+ section (NULL)
+ {
+ }
+
+ VMRange vm_range;
+ Section *section;
+ };
+ SectionList *m_section_list;
+ std::vector<SectionInfo> m_section_infos;
+};
+
+
+
+size_t
+ObjectFileMachO::ParseSymtab (bool minimize)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "ObjectFileMachO::ParseSymtab () module = %s",
+ m_file.GetFilename().AsCString(""));
+ struct symtab_command symtab_load_command;
+ uint32_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t i;
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const uint32_t cmd_offset = offset;
+ // Read in the load command and load command size
+ if (m_data.GetU32(&offset, &symtab_load_command, 2) == NULL)
+ break;
+ // Watch for the symbol table load command
+ if (symtab_load_command.cmd == LC_SYMTAB)
+ {
+ // Read in the rest of the symtab load command
+ if (m_data.GetU32(&offset, &symtab_load_command.symoff, 4))
+ {
+ Symtab *symtab = m_symtab_ap.get();
+ SectionList *section_list = GetSectionList();
+ assert(section_list);
+ const size_t addr_size = m_data.GetAddressByteSize();
+ const ByteOrder endian = m_data.GetByteOrder();
+ bool bit_width_32 = addr_size == 4;
+ const size_t nlist_size = bit_width_32 ? sizeof(struct nlist) : sizeof(struct nlist_64);
+
+ DataBufferSP symtab_data_sp(m_file.ReadFileContents(m_offset + symtab_load_command.symoff, symtab_load_command.nsyms * nlist_size));
+ DataBufferSP strtab_data_sp(m_file.ReadFileContents(m_offset + symtab_load_command.stroff, symtab_load_command.strsize));
+
+ const char *strtab_data = (const char *)strtab_data_sp->GetBytes();
+// DataExtractor symtab_data(symtab_data_sp, endian, addr_size);
+// DataExtractor strtab_data(strtab_data_sp, endian, addr_size);
+
+ static ConstString g_segment_name_TEXT ("__TEXT");
+ static ConstString g_segment_name_DATA ("__DATA");
+ static ConstString g_segment_name_OBJC ("__OBJC");
+ static ConstString g_section_name_eh_frame ("__eh_frame");
+ SectionSP text_section_sp(section_list->FindSectionByName(g_segment_name_TEXT));
+ SectionSP data_section_sp(section_list->FindSectionByName(g_segment_name_DATA));
+ SectionSP objc_section_sp(section_list->FindSectionByName(g_segment_name_OBJC));
+ SectionSP eh_frame_section_sp;
+ if (text_section_sp.get())
+ eh_frame_section_sp = text_section_sp->GetChildren().FindSectionByName (g_section_name_eh_frame);
+ else
+ eh_frame_section_sp = section_list->FindSectionByName (g_section_name_eh_frame);
+
+ uint8_t TEXT_eh_frame_sectID = eh_frame_section_sp.get() ? eh_frame_section_sp->GetID() : NO_SECT;
+ //uint32_t symtab_offset = 0;
+ const uint8_t* nlist_data = symtab_data_sp->GetBytes();
+ assert (symtab_data_sp->GetByteSize()/nlist_size >= symtab_load_command.nsyms);
+
+
+ if (endian != eByteOrderHost)
+ {
+ // ...
+ assert (!"UNIMPLEMENTED: Swap all nlist entries");
+ }
+ uint32_t N_SO_index = UINT_MAX;
+
+ MachSymtabSectionInfo section_info (section_list);
+ std::vector<uint32_t> N_FUN_indexes;
+ std::vector<uint32_t> N_NSYM_indexes;
+ std::vector<uint32_t> N_INCL_indexes;
+ std::vector<uint32_t> N_BRAC_indexes;
+ std::vector<uint32_t> N_COMM_indexes;
+ uint32_t nlist_idx = 0;
+ Symbol *symbol_ptr = NULL;
+
+ uint32_t sym_idx = 0;
+ Symbol *sym = symtab->Resize (symtab_load_command.nsyms + m_dysymtab.nindirectsyms);
+ uint32_t num_syms = symtab->GetNumSymbols();
+
+ //symtab->Reserve (symtab_load_command.nsyms + m_dysymtab.nindirectsyms);
+ for (nlist_idx = 0; nlist_idx < symtab_load_command.nsyms; ++nlist_idx)
+ {
+ struct nlist_64 nlist;
+ if (bit_width_32)
+ {
+ struct nlist* nlist32_ptr = (struct nlist*)(nlist_data + (nlist_idx * nlist_size));
+ nlist.n_un.n_strx = nlist32_ptr->n_un.n_strx;
+ nlist.n_type = nlist32_ptr->n_type;
+ nlist.n_sect = nlist32_ptr->n_sect;
+ nlist.n_desc = nlist32_ptr->n_desc;
+ nlist.n_value = nlist32_ptr->n_value;
+ }
+ else
+ {
+ nlist = *((struct nlist_64*)(nlist_data + (nlist_idx * nlist_size)));
+ }
+
+ SymbolType type = eSymbolTypeInvalid;
+ const char* symbol_name = &strtab_data[nlist.n_un.n_strx];
+ if (symbol_name[0] == '\0')
+ symbol_name = NULL;
+ Section* symbol_section = NULL;
+ bool add_nlist = true;
+ bool is_debug = ((nlist.n_type & N_STAB) != 0);
+
+ assert (sym_idx < num_syms);
+
+ sym[sym_idx].SetDebug (is_debug);
+
+ if (is_debug)
+ {
+ switch (nlist.n_type)
+ {
+ case N_GSYM: // global symbol: name,,NO_SECT,type,0
+ // Sometimes the N_GSYM value contains the address.
+ if (nlist.n_value != 0)
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeGlobal;
+ break;
+
+ case N_FNAME: // procedure name (f77 kludge): name,,NO_SECT,0,0
+ type = eSymbolTypeFunction;
+ break;
+
+ case N_FUN: // procedure: name,,n_sect,linenumber,address
+ if (symbol_name)
+ {
+ type = eSymbolTypeFunction;
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ N_FUN_indexes.push_back(sym_idx);
+ }
+ else
+ {
+ type = eSymbolTypeFunctionEnd;
+
+ if ( !N_FUN_indexes.empty() )
+ {
+ // Copy the size of the function into the original STAB entry so we don't have
+ // to hunt for it later
+ symtab->SymbolAtIndex(N_FUN_indexes.back())->SetByteSize(nlist.n_value);
+ N_FUN_indexes.pop_back();
+ // We dont' really need the end function STAB as it contains the size which
+ // we already placed with the original symbol, so don't add it if we want a
+ // minimal symbol table
+ if (minimize)
+ add_nlist = false;
+ }
+ }
+ break;
+
+ case N_STSYM: // static symbol: name,,n_sect,type,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeStatic;
+ break;
+
+ case N_LCSYM: // .lcomm symbol: name,,n_sect,type,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeCommonBlock;
+ break;
+
+ case N_BNSYM:
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ if (minimize)
+ {
+ // Skip these if we want minimal symbol tables
+ add_nlist = false;
+ }
+ else
+ {
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ N_NSYM_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ }
+ break;
+
+ case N_ENSYM:
+ // Set the size of the N_BNSYM to the terminating index of this N_ENSYM
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ if (minimize)
+ {
+ // Skip these if we want minimal symbol tables
+ add_nlist = false;
+ }
+ else
+ {
+ if ( !N_NSYM_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_NSYM_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_NSYM_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ }
+ break;
+
+
+ case N_OPT: // emitted with gcc2_compiled and in gcc source
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_RSYM: // register sym: name,,NO_SECT,type,register
+ type = eSymbolTypeVariable;
+ break;
+
+ case N_SLINE: // src line: 0,,n_sect,linenumber,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeLineEntry;
+ break;
+
+ case N_SSYM: // structure elt: name,,NO_SECT,type,struct_offset
+ type = eSymbolTypeVariableType;
+ break;
+
+ case N_SO:
+ type = eSymbolTypeSourceFile;
+ if (symbol_name == NULL)
+ {
+ if (N_SO_index == UINT_MAX)
+ {
+ // Skip the extra blank N_SO entries that happen when the entire
+ // path is contained in the second consecutive N_SO STAB.
+ if (minimize)
+ add_nlist = false;
+ }
+ else
+ {
+ // Set the size of the N_SO to the terminating index of this N_SO
+ // so that we can always skip the entire N_SO if we need to navigate
+ // more quickly at the source level when parsing STABS
+ symbol_ptr = symtab->SymbolAtIndex(N_SO_index);
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ }
+ N_NSYM_indexes.clear();
+ N_INCL_indexes.clear();
+ N_BRAC_indexes.clear();
+ N_COMM_indexes.clear();
+ N_FUN_indexes.clear();
+ N_SO_index = UINT_MAX;
+ }
+ else if (symbol_name[0] == '/')
+ {
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ N_SO_index = sym_idx;
+ }
+ break;
+
+ case N_OSO: // object file name: name,,0,0,st_mtime
+ type = eSymbolTypeObjectFile;
+ break;
+
+ case N_LSYM: // local sym: name,,NO_SECT,type,offset
+ type = eSymbolTypeLocal;
+ break;
+
+ //----------------------------------------------------------------------
+ // INCL scopes
+ //----------------------------------------------------------------------
+ case N_BINCL: // include file beginning: name,,NO_SECT,0,sum
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ N_INCL_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ break;
+ case N_EINCL: // include file end: name,,NO_SECT,0,0
+
+ // Set the size of the N_BINCL to the terminating index of this N_EINCL
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ if ( !N_INCL_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_INCL_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_SOL: // #included file name: name,,n_sect,0,address
+ type = eSymbolTypeHeaderFile;
+ break;
+
+ case N_PARAMS: // compiler parameters: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_VERSION: // compiler version: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_OLEVEL: // compiler -O level: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_PSYM: // parameter: name,,NO_SECT,type,offset
+ type = eSymbolTypeVariable;
+ break;
+
+ case N_ENTRY: // alternate entry: name,,n_sect,linenumber,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeLineEntry;
+ break;
+
+ //----------------------------------------------------------------------
+ // Left and Right Braces
+ //----------------------------------------------------------------------
+ case N_LBRAC: // left bracket: 0,,NO_SECT,nesting level,address
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ N_BRAC_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ break;
+
+ case N_RBRAC: // right bracket: 0,,NO_SECT,nesting level,address
+ // Set the size of the N_LBRAC to the terminating index of this N_RBRAC
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ if ( !N_BRAC_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_BRAC_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_EXCL: // deleted include file: name,,NO_SECT,0,sum
+ type = eSymbolTypeHeaderFile;
+ break;
+
+ //----------------------------------------------------------------------
+ // COMM scopes
+ //----------------------------------------------------------------------
+ case N_BCOMM: // begin common: name,,NO_SECT,0,0
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ type = eSymbolTypeScopeBegin;
+ N_COMM_indexes.push_back(sym_idx);
+ break;
+
+ case N_ECOML: // end common (local name): 0,,n_sect,0,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ // Fall through
+
+ case N_ECOMM: // end common: name,,n_sect,0,0
+ // Set the size of the N_BCOMM to the terminating index of this N_ECOMM/N_ECOML
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ if ( !N_COMM_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_COMM_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_LENG: // second stab entry with length information
+ type = eSymbolTypeAdditional;
+ break;
+
+ default: break;
+ }
+ }
+ else
+ {
+ //uint8_t n_pext = N_PEXT & nlist.n_type;
+ uint8_t n_type = N_TYPE & nlist.n_type;
+ sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0);
+
+ if (symbol_name && ::strstr (symbol_name, ".objc") == symbol_name)
+ {
+ type = eSymbolTypeRuntime;
+ }
+ else
+ {
+ switch (n_type)
+ {
+ case N_INDR: // Fall through
+ case N_PBUD: // Fall through
+ case N_UNDF:
+ type = eSymbolTypeExtern;
+ break;
+
+ case N_ABS:
+ type = eSymbolTypeAbsolute;
+ break;
+
+ case N_SECT:
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+
+ assert(symbol_section != NULL);
+ if (TEXT_eh_frame_sectID == nlist.n_sect)
+ {
+ type = eSymbolTypeException;
+ }
+ else
+ {
+ uint32_t section_type = symbol_section->GetAllFlagBits() & SECTION_TYPE;
+
+ switch (section_type)
+ {
+ case S_REGULAR: break; // regular section
+ //case S_ZEROFILL: type = eSymbolTypeData; break; // zero fill on demand section
+ case S_CSTRING_LITERALS: type = eSymbolTypeData; break; // section with only literal C strings
+ case S_4BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 4 byte literals
+ case S_8BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 8 byte literals
+ case S_LITERAL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only pointers to literals
+ case S_NON_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only non-lazy symbol pointers
+ case S_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only lazy symbol pointers
+ case S_SYMBOL_STUBS: type = eSymbolTypeTrampoline; break; // section with only symbol stubs, byte size of stub in the reserved2 field
+ case S_MOD_INIT_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for initialization
+ case S_MOD_TERM_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for termination
+ //case S_COALESCED: type = eSymbolType; break; // section contains symbols that are to be coalesced
+ //case S_GB_ZEROFILL: type = eSymbolTypeData; break; // zero fill on demand section (that can be larger than 4 gigabytes)
+ case S_INTERPOSING: type = eSymbolTypeTrampoline; break; // section with only pairs of function pointers for interposing
+ case S_16BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 16 byte literals
+ case S_DTRACE_DOF: type = eSymbolTypeInstrumentation; break;
+ case S_LAZY_DYLIB_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break;
+ default: break;
+ }
+
+ if (type == eSymbolTypeInvalid)
+ {
+ const char *symbol_sect_name = symbol_section->GetName().AsCString();
+ if (symbol_section->IsDescendant (text_section_sp.get()))
+ {
+ if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE | S_ATTR_SOME_INSTRUCTIONS))
+ type = eSymbolTypeData;
+ else
+ type = eSymbolTypeCode;
+ }
+ else
+ if (symbol_section->IsDescendant(data_section_sp.get()))
+ {
+ if (symbol_sect_name && ::strstr (symbol_sect_name, "__objc") == symbol_sect_name)
+ {
+ type = eSymbolTypeRuntime;
+ }
+ else
+ if (symbol_sect_name && ::strstr (symbol_sect_name, "__gcc_except_tab") == symbol_sect_name)
+ {
+ type = eSymbolTypeException;
+ }
+ else
+ {
+ type = eSymbolTypeData;
+ }
+ }
+ else
+ if (symbol_sect_name && ::strstr (symbol_sect_name, "__IMPORT") == symbol_sect_name)
+ {
+ type = eSymbolTypeTrampoline;
+ }
+ else
+ if (symbol_section->IsDescendant(objc_section_sp.get()))
+ {
+ type = eSymbolTypeRuntime;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (add_nlist)
+ {
+ bool symbol_name_is_mangled = false;
+ if (symbol_name && symbol_name[0] == '_')
+ {
+ symbol_name_is_mangled = symbol_name[1] == '_';
+ symbol_name++; // Skip the leading underscore
+ }
+ uint64_t symbol_value = nlist.n_value;
+ if (symbol_section != NULL)
+ symbol_value -= symbol_section->GetFileAddress();
+
+ sym[sym_idx].SetID (nlist_idx);
+ sym[sym_idx].SetType (type);
+ if (symbol_name)
+ sym[sym_idx].GetMangled().SetValue(symbol_name, symbol_name_is_mangled);
+ sym[sym_idx].GetAddressRangeRef().GetBaseAddress().SetSection (symbol_section);
+ sym[sym_idx].GetAddressRangeRef().GetBaseAddress().SetOffset (symbol_value);
+ sym[sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc);
+
+ ++sym_idx;
+ }
+ else
+ {
+ sym[sym_idx].Clear();
+ }
+
+ }
+
+
+ // STAB N_GSYM entries end up having a symbol type eSymbolTypeGlobal and when the symbol value
+ // is zero, the address of the global ends up being in a non-STAB entry. Try and fix up all
+ // such entries by figuring out what the address for the global is by looking up this non-STAB
+ // entry and copying the value into the debug symbol's value to save us the hassle in the
+ // debug symbol parser.
+
+ Symbol *global_symbol = NULL;
+ for (nlist_idx = 0;
+ nlist_idx < symtab_load_command.nsyms && (global_symbol = symtab->FindSymbolWithType(eSymbolTypeGlobal, nlist_idx)) != NULL;
+ nlist_idx++)
+ {
+ if (global_symbol->GetValue().GetFileAddress() == 0)
+ {
+ std::vector<uint32_t> indexes;
+ if (symtab->AppendSymbolIndexesWithName(global_symbol->GetMangled().GetName(), indexes) > 0)
+ {
+ std::vector<uint32_t>::const_iterator pos;
+ std::vector<uint32_t>::const_iterator end = indexes.end();
+ for (pos = indexes.begin(); pos != end; ++pos)
+ {
+ symbol_ptr = symtab->SymbolAtIndex(*pos);
+ if (symbol_ptr != global_symbol && symbol_ptr->IsDebug() == false)
+ {
+ global_symbol->SetValue(symbol_ptr->GetValue());
+ break;
+ }
+ }
+ }
+ }
+ }
+ // Now synthesize indirect symbols
+ if (m_dysymtab.nindirectsyms != 0)
+ {
+ DataBufferSP indirect_symbol_indexes_sp(m_file.ReadFileContents(m_offset + m_dysymtab.indirectsymoff, m_dysymtab.nindirectsyms * 4));
+
+ if (indirect_symbol_indexes_sp && indirect_symbol_indexes_sp->GetByteSize())
+ {
+ DataExtractor indirect_symbol_index_data (indirect_symbol_indexes_sp, m_data.GetByteOrder(), m_data.GetAddressByteSize());
+
+ for (uint32_t sect_idx = 1; sect_idx < m_mach_sections.size(); ++sect_idx)
+ {
+ if ((m_mach_sections[sect_idx].flags & SECTION_TYPE) == S_SYMBOL_STUBS)
+ {
+ uint32_t symbol_stub_byte_size = m_mach_sections[sect_idx].reserved2;
+ if (symbol_stub_byte_size == 0)
+ continue;
+
+ const uint32_t num_symbol_stubs = m_mach_sections[sect_idx].size / symbol_stub_byte_size;
+
+ if (num_symbol_stubs == 0)
+ continue;
+
+ const uint32_t symbol_stub_index_offset = m_mach_sections[sect_idx].reserved1;
+ uint32_t stub_sym_id = symtab_load_command.nsyms;
+ for (uint32_t stub_idx = 0; stub_idx < num_symbol_stubs; ++stub_idx)
+ {
+ const uint32_t symbol_stub_index = symbol_stub_index_offset + stub_idx;
+ const lldb::addr_t symbol_stub_addr = m_mach_sections[sect_idx].addr + (stub_idx * symbol_stub_byte_size);
+ uint32_t symbol_stub_offset = symbol_stub_index * 4;
+ if (indirect_symbol_index_data.ValidOffsetForDataOfSize(symbol_stub_offset, 4))
+ {
+ const uint32_t symbol_index = indirect_symbol_index_data.GetU32 (&symbol_stub_offset);
+
+ Symbol *stub_symbol = symtab->SymbolAtIndex(symbol_index);
+ if (stub_symbol)
+ {
+ Address so_addr(symbol_stub_addr, section_list);
+
+ if (stub_symbol->GetType() == eSymbolTypeExtern)
+ {
+ // Change the external symbol into a trampoline that makes sense
+ // These symbols were N_UNDF N_EXT, and are useless to us, so we
+ // can re-use them so we don't have to make up a synthetic symbol
+ // for no good reason.
+ stub_symbol->SetType (eSymbolTypeTrampoline);
+ stub_symbol->SetExternal (false);
+ stub_symbol->GetAddressRangeRef().GetBaseAddress() = so_addr;
+ stub_symbol->GetAddressRangeRef().SetByteSize (symbol_stub_byte_size);
+ }
+ else
+ {
+ // Make a synthetic symbol to describe the trampoline stub
+ if (sym_idx >= num_syms)
+ {
+ sym = symtab->Resize (num_syms + 16);
+ num_syms = symtab->GetNumSymbols();
+ }
+ sym[sym_idx].SetID (stub_sym_id++);
+ sym[sym_idx].GetMangled() = stub_symbol->GetMangled();
+ sym[sym_idx].SetType (eSymbolTypeTrampoline);
+ sym[sym_idx].SetIsSynthetic (true);
+ sym[sym_idx].GetAddressRangeRef().GetBaseAddress() = so_addr;
+ sym[sym_idx].GetAddressRangeRef().SetByteSize (symbol_stub_byte_size);
+ ++sym_idx;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (sym_idx != symtab->GetNumSymbols())
+ symtab->Resize (sym_idx);
+
+ return symtab->GetNumSymbols();
+ }
+ }
+ offset = cmd_offset + symtab_load_command.cmdsize;
+ }
+ return 0;
+}
+
+
+void
+ObjectFileMachO::Dump (Stream *s)
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ if (m_header.magic == MH_MAGIC_64 || m_header.magic == MH_CIGAM_64)
+ s->PutCString("ObjectFileMachO64");
+ else
+ s->PutCString("ObjectFileMachO32");
+
+ ArchSpec header_arch(m_header.cputype, m_header.cpusubtype);
+
+ *s << ", file = '" << m_file << "', arch = " << header_arch.AsCString() << "\n";
+
+ if (m_sections_ap.get())
+ m_sections_ap->Dump(s, NULL, true);
+
+ if (m_symtab_ap.get())
+ m_symtab_ap->Dump(s, NULL);
+}
+
+
+bool
+ObjectFileMachO::GetUUID (UUID* uuid)
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ struct uuid_command load_cmd;
+ uint32_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t i;
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const uint32_t cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ if (load_cmd.cmd == LC_UUID)
+ {
+ const uint8_t *uuid_bytes = m_data.PeekData(offset, 16);
+ if (uuid_bytes)
+ {
+ uuid->SetBytes (uuid_bytes);
+ return true;
+ }
+ return false;
+ }
+ offset = cmd_offset + load_cmd.cmdsize;
+ }
+ return false;
+}
+
+
+uint32_t
+ObjectFileMachO::GetDependentModules (FileSpecList& files)
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ struct load_command load_cmd;
+ uint32_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t count = 0;
+ uint32_t i;
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const uint32_t cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ switch (load_cmd.cmd)
+ {
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_REEXPORT_DYLIB:
+ case LC_LOAD_DYLINKER:
+ case LC_LOADFVMLIB:
+ {
+ uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
+ const char *path = m_data.PeekCStr(name_offset);
+ // Skip any path that starts with '@' since these are usually:
+ // @executable_path/.../file
+ // @rpath/.../file
+ if (path && path[0] != '@')
+ {
+ FileSpec file_spec(path);
+ if (files.AppendIfUnique(file_spec))
+ count++;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ offset = cmd_offset + load_cmd.cmdsize;
+ }
+ return count;
+}
+
+bool
+ObjectFileMachO::GetTargetTriple (ConstString &target_triple)
+{
+ lldb_private::Mutex::Locker locker(m_mutex);
+ std::string triple(GetModule()->GetArchitecture().AsCString());
+ triple += "-apple-darwin";
+ target_triple.SetCString(triple.c_str());
+ if (target_triple)
+ return true;
+ return false;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ObjectFileMachO::GetPluginName()
+{
+ return "ObjectFileMachO";
+}
+
+const char *
+ObjectFileMachO::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectFileMachO::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ObjectFileMachO::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ObjectFileMachO::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ObjectFileMachO::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
+
+
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
new file mode 100644
index 00000000000..3ffeb242b7c
--- /dev/null
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
@@ -0,0 +1,131 @@
+//===-- ObjectFileMachO.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ObjectFileMachO_h_
+#define liblldb_ObjectFileMachO_h_
+
+#include <mach-o/loader.h>
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+//----------------------------------------------------------------------
+// This class needs to be hidden as eventually belongs in a plugin that
+// will export the ObjectFile protocol
+//----------------------------------------------------------------------
+class ObjectFileMachO :
+ public lldb_private::ObjectFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static ObjectFile *
+ CreateInstance (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec* file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ static bool
+ MagicBytesMatch (lldb::DataBufferSP& dataSP);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ ObjectFileMachO (lldb_private::Module* module,
+ lldb::DataBufferSP& dataSP,
+ const lldb_private::FileSpec* file,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ virtual
+ ~ObjectFileMachO();
+
+ virtual bool
+ ParseHeader ();
+
+ virtual lldb::ByteOrder
+ GetByteOrder () const;
+
+ virtual size_t
+ GetAddressByteSize () const;
+
+ virtual lldb_private::Symtab *
+ GetSymtab();
+
+ virtual lldb_private::SectionList *
+ GetSectionList();
+
+ virtual void
+ Dump (lldb_private::Stream *s);
+
+ virtual bool
+ GetTargetTriple (lldb_private::ConstString &target_triple);
+
+ virtual bool
+ GetUUID (lldb_private::UUID* uuid);
+
+ virtual uint32_t
+ GetDependentModules (lldb_private::FileSpecList& files);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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:
+ mutable lldb_private::Mutex m_mutex;
+ struct mach_header m_header;
+ mutable std::auto_ptr<lldb_private::SectionList> m_sections_ap;
+ mutable std::auto_ptr<lldb_private::Symtab> m_symtab_ap;
+
+ struct dysymtab_command m_dysymtab;
+ std::vector<struct segment_command_64> m_mach_segments;
+ std::vector<struct section_64> m_mach_sections;
+
+ size_t
+ ParseSections ();
+
+ size_t
+ ParseSymtab (bool minimize);
+
+};
+
+#endif // liblldb_ObjectFileMachO_h_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/scripts/cc-swig b/lldb/source/Plugins/Process/MacOSX-User/scripts/cc-swig
new file mode 100644
index 00000000000..0bb089a653e
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/scripts/cc-swig
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+
+use File::Basename;
+
+sub execute_command
+{
+ print join(' ', @_), "\n";
+ if (scalar(@_) > 0) {
+ system(@_);
+ } else {
+ system($_[0]);
+ }
+}
+
+my $infile = $ENV{SCRIPT_INPUT_FILE_1};
+my($in_basename, $in_dirname, $in_extension) = fileparse($infile, qr/\.[^.]*/);
+my $outdir = "$ENV{DERIVED_FILE_DIR}";
+my $perl_wrap_c = "$outdir/${in_basename}_perl_wrap.c";
+mkdir "$ENV{OBJECT_FILE_DIR}";
+my $perl_wrap_o = "$ENV{OBJECT_FILE_DIR}/${in_basename}_perl_wrap.o";
+my $perl_module = "$outdir/${in_basename}.pm";
+my $header_paths = "-I'../../../../../debugcore/source' -I'../../../../../DebugBase'";
+my $framework_opts = "-F'$ENV{CONFIGURATION_BUILD_DIR}' ";
+execute_command("/usr/bin/swig -shadow -perl5 -DHAS_BOOL $header_paths -outdir '$outdir' -o '$perl_wrap_c' '$infile'");
+
+# Get any needed perl options for the next compile
+my $ccopts = `perl -MExtUtils::Embed -e ccopts`;
+my $libperl_dir = undef;
+if ($ccopts =~ /-I(\/System.*CORE)/)
+{
+ $libperl_dir = $1;
+ print "libperl directory: '$libperl_dir'\n";
+}
+
+execute_command("cd '$ENV{OBJECT_FILE_DIR}' && ln -s '$libperl_dir/libperl.dylib'");
+
+
+# Strip out the default architectures it gave us, we will add them back with
+# the $arch_opts below
+$ccopts =~ s/-arch [a-z_0-9]+//g;
+
+# Get a list of our build architectures
+my $arch_opts = "-arch " . join(' -arch ', split('\s+', $ENV{ARCHS}));
+
+execute_command("gcc -c -Dbool=char $arch_opts $ccopts $header_paths $framework_opts -I'$ENV{PROJECT_DIR}/source' '$perl_wrap_c' -o '$perl_wrap_o'");
+
+execute_command("cp '$perl_module' '$ENV{CONFIGURATION_BUILD_DIR}/$ENV{SHARED_SUPPORT_FOLDER_PATH}'"); \ No newline at end of file
diff --git a/lldb/source/Plugins/Process/MacOSX-User/scripts/config.pl b/lldb/source/Plugins/Process/MacOSX-User/scripts/config.pl
new file mode 100644
index 00000000000..a6cf6ce2396
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/scripts/config.pl
@@ -0,0 +1,71 @@
+#!/usr/bin/perl
+
+use strict;
+my $config_file = "$ENV{SCRIPT_OUTPUT_FILE_0}";
+
+# Define the tests we need to run during this configuration
+my @config_tests = (
+ {
+ NAME => "HAVE_64_BIT_MACH_EXCEPTIONS",
+ TEST => "-e '$ENV{SDKROOT}/usr/include/mach/mach_exc.defs'",
+ COMMENT => "// Defined if we can use 64 bit mach exceptions",
+ FAIL => "#undef HAVE_64_BIT_MACH_EXCEPTIONS\
+#define mach_exception_data_t exception_data_t\
+#define mach_exception_data_type_t exception_data_type_t\
+#define mach_exc_server exc_server\
+#define MACH_EXCEPTION_CODES 0\n",
+ SUCCESS => "#define HAVE_64_BIT_MACH_EXCEPTIONS 1\n",
+ }
+);
+
+#----------------------------------------------------------------------
+# Open the config file
+#----------------------------------------------------------------------
+open(CONFIG, "> $config_file") || die "Couldn't open '$config_file' for writing: $!\n";
+print CONFIG "/*" . "-" x 72 . "\n";
+print CONFIG "// This file is auto generated by a config.pl, do not edit by hand!\n";
+print CONFIG "//" . "-" x 72 . "\n";
+print CONFIG "// COMMAND LINE\n";
+print CONFIG "// " . join(' ', @ARGV) . "\n";
+print CONFIG "//" . "-" x 72 . "\n";
+print CONFIG "// ENVIRONMENT\n";
+my $key;
+my $val;
+while (($key, $val) = each %ENV)
+{
+ printf CONFIG "// %s = %s\n", $key, $val;
+}
+print CONFIG "//" . "-" x 72 . "\n";
+print CONFIG "// SETTINGS\n";
+print CONFIG "// config_file: '$config_file'\n";
+print CONFIG "//" . "-" x 72 . "\n";
+print CONFIG "*/\n\n";
+print CONFIG "#ifndef liblldb_PDConfig_h_\n";
+print CONFIG "#define liblldb_PDConfig_h_\n";
+
+
+#----------------------------------------------------------------------
+# Run the tests
+#----------------------------------------------------------------------
+foreach my $test_href (@config_tests)
+{
+ if (exists $test_href->{COMMENT}) {
+ print CONFIG "\n$test_href->{COMMENT}\n";
+ } else {
+ print CONFIG "\n// $test_href->{NAME}\n";
+ }
+
+ my $test_result = eval "$test_href->{TEST}";
+ if ($test_result != 0)
+ {
+ print CONFIG "$test_href->{SUCCESS}\n";
+ }
+ else
+ {
+ print CONFIG "$test_href->{FAIL}\n";
+ }
+}
+
+print CONFIG "#endif // #ifndef liblldb_PDConfig_h_\n";
+close(CONFIG);
+
diff --git a/lldb/source/Plugins/Process/MacOSX-User/scripts/test-ProcessDebug.pl b/lldb/source/Plugins/Process/MacOSX-User/scripts/test-ProcessDebug.pl
new file mode 100755
index 00000000000..96b3115c912
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/scripts/test-ProcessDebug.pl
@@ -0,0 +1,409 @@
+#!/usr/bin/perl
+
+use strict;
+use Cwd 'abs_path';
+our $home = $ENV{HOME} || die "ERROR: Couldn't deduce your home directory...\n";
+
+our @inc_paths = (
+ './include',
+);
+
+my $inc_paths_added = 0;
+foreach my $inc_path (@inc_paths)
+{
+ if (-e $inc_path)
+ {
+ push (@INC, abs_path($inc_path));
+ $inc_paths_added++;
+ }
+}
+
+if ($inc_paths_added == 0)
+{
+ die "Please compile the Release version of lldb\n";
+}
+
+require lldb;
+
+# my $state = lldb::eStateAttaching;
+
+use constant UINT32_MAX => 4294967295;
+
+#----------------------------------------------------------------------
+# Interactive Commands
+#----------------------------------------------------------------------
+our %commands = (
+ break => {
+ name => 'break', # in case an alias is used to get to this command
+ description => "Sets a breakpoint.",
+ usage => ["break ADDR"],
+ function => \&command_set_breakpoint,
+ runs_target => 0,
+ },
+ delete => {
+ name => 'delete', # in case an alias is used to get to this command
+ description => "Deletes one or more breakpoints by ID.\
+If no breakpoint IDs are given all breakpoints will be deleted.\
+If one or more IDs are given, only those breakpoints will be deleted.",
+ usage => ["delete [ID1 ID2 ...]"],
+ function => \&command_clear_breakpoint,
+ runs_target => 0,
+ },
+ continue => {
+ name => 'continue', # in case an alias is used to get to this command
+ description => "Continues target execution.",
+ usage => ["continue [ADDR]"],
+ function => \&command_continue,
+ runs_target => 1
+ },
+ step => {
+ name => 'step', # in case an alias is used to get to this command
+ description => "Single steps one instruction.",
+ usage => ["step"],
+ function => \&command_step,
+ runs_target => 1
+ },
+ info => {
+ name => 'info', # in case an alias is used to get to this command
+ description => "Gets info on a variety of things.",
+ usage => ["info reg", "info thread", "info threads"],
+ function => \&command_info,
+ runs_target => 0
+ },
+ help => {
+ name => 'help', # in case an alias is used to get to this command
+ description => "Displays a list of all commands, or help for a specific command.",
+ usage => ["help", "help CMD"],
+ function => \&command_help,
+ runs_target => 0
+ }
+);
+
+#----------------------------------------------------------------------
+# Command aliases
+#----------------------------------------------------------------------
+our %aliases = (
+ b => $commands{break},
+ c => $commands{continue},
+ s => $commands{step},
+ d => $commands{delete},
+ h => $commands{help}
+);
+
+our $opt_g = 0; # Enable verbose debug logging
+our $opt_v = 0; # Verbose mode
+my $prev_command_href = undef;
+my $stdio = '/dev/stdin';
+my $launch = 0;
+my @env = ();
+my @break_ids;
+
+#----------------------------------------------------------------------
+# Given a command string, return the command hash reference for it, or
+# undef if it doesn't exist.
+#----------------------------------------------------------------------
+sub get_command_hash_ref
+{
+ my $cmd = shift;
+ my $cmd_href = undef;
+ if (length($cmd) == 0) { $cmd_href = $prev_command_href; }
+ elsif (exists $aliases{$cmd}) { $cmd_href = $aliases{$cmd}; }
+ elsif (exists $commands{$cmd}) { $cmd_href = $commands{$cmd}; }
+ defined $cmd_href and $prev_command_href = $cmd_href;
+ return $cmd_href;
+}
+
+#----------------------------------------------------------------------
+# Set a breakpoint
+#----------------------------------------------------------------------
+sub command_set_breakpoint
+{
+ my $pid = shift;
+ my $tid = shift;
+ $opt_g and print "command_set_breakpoint (pid = $pid, locations = @_)\n";
+ foreach my $location (@_)
+ {
+ my $success = 0;
+ my $address = hex($location);
+ if ($address != 0)
+ {
+ my $break_id = lldb::PDBreakpointSet ($pid, $address, 1, 0);
+ if ($break_id != $lldb::PD_INVALID_BREAK_ID)
+ {
+ printf("Breakpoint %i is set.\n", $break_id);
+ push(@break_ids, $break_id);
+ $success = 1;
+ }
+ }
+ $success or print("error: failed to set breakpoint at $location.\n");
+ }
+ return 1;
+}
+
+#----------------------------------------------------------------------
+# Clear a breakpoint
+#----------------------------------------------------------------------
+sub command_clear_breakpoint
+{
+ my $pid = shift;
+ my $tid = shift;
+ if (@_)
+ {
+ my $break_id;
+ my @cleared_break_ids;
+ my @new_break_ids;
+ $opt_g and print "command_clear_breakpoint (pid = $pid, break_ids = @_)\n";
+ foreach $break_id (@_)
+ {
+ if (lldb::PDBreakpointClear ($pid, $break_id))
+ {
+ printf("Breakpoint %i has been cleared.\n", $break_id);
+ push (@cleared_break_ids, $break_id);
+ }
+ else
+ {
+ printf("error: failed to clear breakpoint %i.\n", $break_id);
+ }
+ }
+
+ foreach my $old_break_id (@break_ids)
+ {
+ my $found_break_id = 0;
+ foreach $break_id (@cleared_break_ids)
+ {
+ if ($old_break_id == $break_id)
+ {
+ $found_break_id = 1;
+ }
+ }
+ $found_break_id or push (@new_break_ids, $old_break_id);
+ }
+ @break_ids = @new_break_ids;
+ }
+ else
+ {
+ # Nothing specified, clear all breakpoints
+ return command_clear_breakpoint($pid, $tid, @break_ids);
+ }
+ return 1;
+}
+#----------------------------------------------------------------------
+# Continue program execution
+#----------------------------------------------------------------------
+sub command_continue
+{
+ my $pid = shift;
+ my $tid = shift;
+ $opt_g and print "command_continue (pid = $pid)\n";
+ if ($pid != $lldb::PD_INVALID_PROCESS_ID)
+ {
+ $opt_v and printf("Resuming pid %d...\n", $pid);
+ return lldb::PDProcessResume ($pid);
+ }
+ return 0;
+}
+
+sub command_step
+{
+ my $pid = shift;
+ my $tid = shift;
+ $opt_g and print "command_step (pid = $pid, tid = $tid)\n";
+ if ($pid != $lldb::PD_INVALID_PROCESS_ID)
+ {
+ $opt_v and printf("Single stepping pid %d tid = %4.4x...\n", $pid, $tid);
+ return lldb::PDThreadResume ($pid, $tid, 1);
+ }
+ return 0;
+}
+
+sub command_info
+{
+ my $pid = shift;
+ my $tid = shift;
+ $opt_g and print "command_step (pid = $pid, tid = $tid)\n";
+ if ($pid != $lldb::PD_INVALID_PROCESS_ID)
+ {
+ if (@_)
+ {
+ my $info_cmd = shift;
+ if ($info_cmd eq 'reg')
+ {
+
+ }
+ elsif ($info_cmd eq 'thread')
+ {
+ # info on the current thread
+ printf("thread 0x%4.4x %s\n", $tid, lldb::PDThreadGetInfo($pid, $tid));
+ }
+ elsif ($info_cmd eq 'threads')
+ {
+ my $num_threads = lldb::PDProcessGetNumThreads( $pid );
+ for my $thread_num (1..$num_threads)
+ {
+ my $curr_tid = lldb::PDProcessGetThreadAtIndex ( $pid, $thread_num - 1 );
+ printf("%c%u - thread 0x%4.4x %s\n", $curr_tid == $tid ? '*' : ' ', $thread_num, $curr_tid, lldb::PDThreadGetInfo($pid, $curr_tid));
+ }
+ }
+ }
+ }
+ return 1;
+}
+#----------------------------------------------------------------------
+# Get help on all commands, or a specific list of commands
+#----------------------------------------------------------------------
+sub command_help
+{
+ my $pid = shift;
+ my $tid = shift;
+ if (@_)
+ {
+ $opt_g and print "command_continue (pid = $pid, commands = @_)\n";
+ foreach my $cmd (@_)
+ {
+ my $cmd_href = get_command_hash_ref($cmd);
+ if ($cmd_href)
+ {
+ print '#', '-' x 72, "\n# $cmd_href->{name}\n", '#', '-' x 72, "\n";
+ my $usage_aref = $cmd_href->{usage};
+ if (@{$usage_aref})
+ {
+ print " USAGE\n";
+ foreach my $usage (@{$usage_aref}) {
+ print " $usage\n";
+ }
+ print "\n";
+ }
+ print " DESCRIPTION\n $cmd_href->{description}\n\n";
+ }
+ else
+ {
+ print " invalid command: '$cmd'\n\n";
+ }
+ }
+ }
+ else
+ {
+ return command_help($pid, sort keys %commands);
+ }
+ return 1;
+}
+
+
+#lldb::PDLogSetLogMask ($lldb::PD_LOG_ALL);
+#lldb::PDLogSetLogFile ('/dev/stdout');
+
+print "running: ", join(' ', @ARGV), "\n";
+
+my $pid = lldb::PDProcessLaunch ($ARGV[0], \@ARGV, \@env, "i386", '/dev/stdin', '/dev/stdout', '/dev/stderr', $launch, '', 0);
+my $pid_state;
+while ($pid)
+{
+ $opt_g and printf("PDProcessWaitForEvents (%d, 0x%4.4x, SET, 1)\n", $pid, $lldb::PD_ALL_EVENTS);
+ my $events = lldb::PDProcessWaitForEvents ($pid, $lldb::PD_ALL_EVENTS, 1, 1);
+ if ($events)
+ {
+ $opt_g and printf ("Got event: 0x%8.8x\n", $events);
+
+ if ($events & $lldb::PD_EVENT_IMAGES_CHANGED)
+ {
+ $opt_g and printf("pid %d images changed...\n", $pid);
+ }
+
+ if ($events & $lldb::PD_EVENT_STDIO)
+ {
+ $opt_g and printf("pid %d has stdio...\n", $pid);
+ }
+
+ if ($events & $lldb::PD_EVENT_ASYNC_INTERRUPT)
+ {
+ $opt_g and printf("pid %d got async interrupt...\n", $pid);
+ }
+
+ if ($events & $lldb::PD_EVENT_RUNNING)
+ {
+ $pid_state = lldb::PDProcessGetState ($pid);
+ $opt_v and printf( "pid %d state: %s.\n", $pid, lldb::PDStateAsString ($pid_state) );
+ }
+
+ if ($events & $lldb::PD_EVENT_STOPPED)
+ {
+ $pid_state = lldb::PDProcessGetState ($pid);
+ $opt_v and printf( "pid %d state: %s.\n", $pid, lldb::PDStateAsString ($pid_state) );
+
+ if ($pid_state == $lldb::eStateUnloaded ||
+ $pid_state == $lldb::eStateAttaching ||
+ $pid_state == $lldb::eStateLaunching )
+ {
+
+ }
+ elsif ( $pid_state == $lldb::eStateStopped )
+ {
+ my $tid = lldb::PDProcessGetCurrentThread ( $pid );
+ my $pc = lldb::PDThreadGetRegisterHexValueByName($pid, $tid, $lldb::PD_REGISTER_SET_ALL, "eip", 0);
+ $pc != 0 and printf("pc = 0x%8.8x ", $pc);
+ # my $sp = lldb::PDThreadGetRegisterHexValueByName($pid, $tid, $lldb::PD_REGISTER_SET_ALL, "esp", 0);
+ # $sp != 0 and printf("sp = 0x%8.8x ", $sp);
+ # my $fp = lldb::PDThreadGetRegisterHexValueByName($pid, $tid, $lldb::PD_REGISTER_SET_ALL, "ebp", 0);
+ # $sp != 0 and printf("fp = 0x%8.8x ", $fp);
+ # print "\n";
+ my $done = 0;
+ my $input;
+ while (!$done)
+ {
+ print '(pdbg) ';
+
+ chomp($input = <STDIN>);
+ my @argv = split(/\s+/, $input);
+ my $cmd = @argv ? shift @argv : undef;
+ my $cmd_href = get_command_hash_ref ($cmd);
+ if ($cmd_href)
+ {
+ # Print the expanded alias if one was used
+ if ($opt_v and $cmd_href->{name} ne $cmd)
+ {
+ print "$cmd_href->{name} @argv\n";
+ }
+
+ # Call the command's callback function to make things happen
+ if ($cmd_href->{function}($pid, $tid, @argv))
+ {
+ $done = $cmd_href->{runs_target};
+ }
+ }
+ else
+ {
+ print "invalid command: '$cmd'\nType 'help' for a list of all commands.\nType 'help CMD' for help on a specific commmand.\n";
+ }
+ }
+ }
+ elsif ( $pid_state == $lldb::eStateRunning ||
+ $pid_state == $lldb::eStateStepping )
+ {
+
+ }
+ elsif ( $pid_state == $lldb::eStateCrashed ||
+ $pid_state == $lldb::eStateDetached ||
+ $pid_state == $lldb::eStateExited )
+ {
+ $pid = 0;
+ }
+ elsif ( $pid_state == $lldb::eStateSuspended )
+ {
+ }
+ else
+ {
+ }
+ }
+
+ if ($pid)
+ {
+ $opt_g and printf("PDProcessResetEvents(%d, 0x%8.8x)\n", $pid, $events);
+ lldb::PDProcessResetEvents($pid, $events);
+ }
+ }
+}
+
+if ($pid != $lldb::PD_INVALID_PROCESS_ID)
+{
+ lldb::PDProcessDetach ($pid);
+}
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.cpp
new file mode 100644
index 00000000000..7dc8d2ce652
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.cpp
@@ -0,0 +1,575 @@
+//===-- MachException.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 <sys/types.h>
+#include <sys/ptrace.h>
+
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Host.h"
+
+#include "MachException.h"
+#include "ProcessMacOSXLog.h"
+
+using namespace lldb_private;
+
+// Routine mach_exception_raise
+extern "C"
+kern_return_t catch_mach_exception_raise
+(
+ mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ mach_exception_data_t code,
+ mach_msg_type_number_t codeCnt
+);
+
+extern "C"
+kern_return_t catch_mach_exception_raise_state
+(
+ mach_port_t exception_port,
+ exception_type_t exception,
+ const mach_exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ int *flavor,
+ const thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt
+);
+
+// Routine mach_exception_raise_state_identity
+extern "C"
+kern_return_t catch_mach_exception_raise_state_identity
+(
+ mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ mach_exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ int *flavor,
+ thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt
+);
+
+extern "C" boolean_t mach_exc_server(
+ mach_msg_header_t *InHeadP,
+ mach_msg_header_t *OutHeadP);
+
+// Any access to the g_message variable should be done by locking the
+// g_message_mutex first, using the g_message variable, then unlocking
+// the g_message_mutex. See MachException::Message::CatchExceptionRaise()
+// for sample code.
+
+static MachException::Data *g_message = NULL;
+//static pthread_mutex_t g_message_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+extern "C"
+kern_return_t
+catch_mach_exception_raise_state
+(
+ mach_port_t exc_port,
+ exception_type_t exc_type,
+ const mach_exception_data_t exc_data,
+ mach_msg_type_number_t exc_data_count,
+ int * flavor,
+ const thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t * new_stateCnt
+)
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ if (log)
+ {
+ log->Printf("::%s ( exc_port = 0x%4.4x, exc_type = %d ( %s ), exc_data = " MACH_EXCEPTION_DATA_FMT_HEX ", exc_data_count = %d)",
+ __FUNCTION__,
+ exc_port,
+ exc_type, MachException::Name(exc_type),
+ exc_data,
+ exc_data_count);
+ }
+ return KERN_FAILURE;
+}
+
+extern "C"
+kern_return_t
+catch_mach_exception_raise_state_identity
+(
+ mach_port_t exc_port,
+ mach_port_t thread_port,
+ mach_port_t task_port,
+ exception_type_t exc_type,
+ mach_exception_data_t exc_data,
+ mach_msg_type_number_t exc_data_count,
+ int * flavor,
+ thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt
+)
+{
+ kern_return_t kret;
+ Log * log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ if (log)
+ {
+ log->Printf("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = 0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { " MACH_EXCEPTION_DATA_FMT_HEX ", " MACH_EXCEPTION_DATA_FMT_HEX " })",
+ __FUNCTION__,
+ exc_port,
+ thread_port,
+ task_port,
+ exc_type, MachException::Name(exc_type),
+ exc_data_count,
+ exc_data_count > 0 ? exc_data[0] : 0xBADDBADD,
+ exc_data_count > 1 ? exc_data[1] : 0xBADDBADD);
+ }
+ kret = mach_port_deallocate (mach_task_self (), task_port);
+ kret = mach_port_deallocate (mach_task_self (), thread_port);
+
+ return KERN_FAILURE;
+}
+
+extern "C"
+kern_return_t
+catch_mach_exception_raise
+(
+ mach_port_t exc_port,
+ mach_port_t thread_port,
+ mach_port_t task_port,
+ exception_type_t exc_type,
+ mach_exception_data_t exc_data,
+ mach_msg_type_number_t exc_data_count)
+{
+ Log * log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ if (log)
+ {
+ log->Printf("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = 0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { " MACH_EXCEPTION_DATA_FMT_HEX ", " MACH_EXCEPTION_DATA_FMT_HEX " })",
+ __FUNCTION__,
+ exc_port,
+ thread_port,
+ task_port,
+ exc_type, MachException::Name(exc_type),
+ exc_data_count,
+ exc_data_count > 0 ? exc_data[0] : 0xBADDBADD,
+ exc_data_count > 1 ? exc_data[1] : 0xBADDBADD);
+ }
+
+ g_message->task_port = task_port;
+ g_message->thread_port = thread_port;
+ g_message->exc_type = exc_type;
+ g_message->exc_data.resize(exc_data_count);
+ ::memcpy (&g_message->exc_data[0], exc_data, g_message->exc_data.size() * sizeof (mach_exception_data_type_t));
+ return KERN_SUCCESS;
+}
+
+
+void
+MachException::Message::PutToLog(Log *log) const
+{
+ if (log)
+ {
+ log->Printf(" exc_msg { bits = 0x%8.8lx size = 0x%8.8lx remote-port = 0x%8.8lx local-port = 0x%8.8lx reserved = 0x%8.8lx id = 0x%8.8lx } ",
+ exc_msg.hdr.msgh_bits,
+ exc_msg.hdr.msgh_size,
+ exc_msg.hdr.msgh_remote_port,
+ exc_msg.hdr.msgh_local_port,
+ exc_msg.hdr.msgh_reserved,
+ exc_msg.hdr.msgh_id);
+
+ log->Printf( "reply_msg { bits = 0x%8.8lx size = 0x%8.8lx remote-port = 0x%8.8lx local-port = 0x%8.8lx reserved = 0x%8.8lx id = 0x%8.8lx }",
+ reply_msg.hdr.msgh_bits,
+ reply_msg.hdr.msgh_size,
+ reply_msg.hdr.msgh_remote_port,
+ reply_msg.hdr.msgh_local_port,
+ reply_msg.hdr.msgh_reserved,
+ reply_msg.hdr.msgh_id);
+ state.PutToLog(log);
+ }
+}
+
+bool
+MachException::Data::GetStopInfo(Thread::StopInfo *stop_info) const
+{
+ // Zero out the structure.
+ stop_info->Clear();
+
+ // Make sure we have a valid exception before we return anything valid
+ if (exc_type == 0)
+ return true;
+ // We always stop with a mach exceptions
+ const size_t exc_data_count = exc_data.size();
+ stop_info->SetStopReasonWithException(exc_type, exc_data_count);
+
+ // Fill in a text description
+ const char * exc_name = MachException::Name(exc_type);
+ StreamString sstr;
+ if (exc_name)
+ sstr.PutCString(exc_name);
+ else
+ sstr.Printf ("%i", exc_type);
+
+ int signal = SoftSignal();
+ if (signal > 0)
+ {
+ const char *sig_str = Host::GetSignalAsCString(signal);
+ if (sig_str)
+ sstr.Printf (" EXC_SOFT_SIGNAL(%s)", sig_str);
+ else
+ sstr.Printf (" EXC_SOFT_SIGNAL(%i)", signal);
+ }
+ else
+ {
+ // No special disassembly for exception data, just
+ sstr.Printf (" data[%zu] = {", exc_data_count);
+
+ for (size_t idx = 0; idx < exc_data_count; ++idx)
+ sstr.Printf (MACH_EXCEPTION_DATA_FMT_MINHEX "%s", exc_data[idx], ((idx + 1 == exc_data_count) ? "" : ","));
+
+ sstr.PutChar('}');
+ }
+
+ stop_info->SetStopDescription (sstr.GetData());
+
+ // Copy the exception data
+ size_t i;
+ for (i=0; i<exc_data_count; i++)
+ stop_info->SetExceptionDataAtIndex(i, exc_data[i]);
+
+ return true;
+}
+
+
+void
+MachException::Data::DumpStopReason() const
+{
+ Log * log = ProcessMacOSXLog::GetLogIfAllCategoriesSet();
+ if (log)
+ {
+ int signal = SoftSignal();
+ if (signal > 0)
+ {
+ const char *signal_str = Host::GetSignalAsCString(signal);
+ if (signal_str)
+ log->Printf ("signal(%s)", signal_str);
+ else
+ log->Printf ("signal(%i)", signal);
+ return;
+ }
+ log->Printf ("%s", Name(exc_type));
+ }
+}
+
+kern_return_t
+MachException::Message::Receive(mach_port_t port, mach_msg_option_t options, mach_msg_timeout_t timeout, mach_port_t notify_port)
+{
+ Error err;
+ Log * log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ mach_msg_timeout_t mach_msg_timeout = options & MACH_RCV_TIMEOUT ? timeout : 0;
+ if (log && ((options & MACH_RCV_TIMEOUT) == 0))
+ {
+ // Dump this log message if we have no timeout in case it never returns
+ log->Printf ("::mach_msg ( msg->{bits = %#x, size = %u remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x)",
+ exc_msg.hdr.msgh_bits,
+ exc_msg.hdr.msgh_size,
+ exc_msg.hdr.msgh_remote_port,
+ exc_msg.hdr.msgh_local_port,
+ exc_msg.hdr.msgh_reserved,
+ exc_msg.hdr.msgh_id,
+ options,
+ 0,
+ sizeof (exc_msg.data),
+ port,
+ mach_msg_timeout,
+ notify_port);
+ }
+
+ err = ::mach_msg (&exc_msg.hdr,
+ options, // options
+ 0, // Send size
+ sizeof (exc_msg.data), // Receive size
+ port, // exception port to watch for exception on
+ mach_msg_timeout, // timeout in msec (obeyed only if MACH_RCV_TIMEOUT is ORed into the options parameter)
+ notify_port);
+
+ // Dump any errors we get
+ if (log && err.GetError() != MACH_RCV_TIMED_OUT)
+ {
+ log->Error("::mach_msg ( msg->{bits = %#x, size = %u remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x)",
+ exc_msg.hdr.msgh_bits,
+ exc_msg.hdr.msgh_size,
+ exc_msg.hdr.msgh_remote_port,
+ exc_msg.hdr.msgh_local_port,
+ exc_msg.hdr.msgh_reserved,
+ exc_msg.hdr.msgh_id,
+ options,
+ 0,
+ sizeof (exc_msg.data),
+ port,
+ mach_msg_timeout,
+ notify_port);
+ }
+ return err.GetError();
+}
+
+bool
+MachException::Message::CatchExceptionRaise()
+{
+ bool success = false;
+ // locker will keep a mutex locked until it goes out of scope
+// Mutex::Locker locker(&g_message_mutex);
+ // log->Printf ("calling mach_exc_server");
+ g_message = &state;
+ // The exc_server function is the MIG generated server handling function
+ // to handle messages from the kernel relating to the occurrence of an
+ // exception in a thread. Such messages are delivered to the exception port
+ // set via thread_set_exception_ports or task_set_exception_ports. When an
+ // exception occurs in a thread, the thread sends an exception message to
+ // its exception port, blocking in the kernel waiting for the receipt of a
+ // reply. The exc_server function performs all necessary argument handling
+ // for this kernel message and calls catch_exception_raise,
+ // catch_exception_raise_state or catch_exception_raise_state_identity,
+ // which should handle the exception. If the called routine returns
+ // KERN_SUCCESS, a reply message will be sent, allowing the thread to
+ // continue from the point of the exception; otherwise, no reply message
+ // is sent and the called routine must have dealt with the exception
+ // thread directly.
+ if (mach_exc_server (&exc_msg.hdr, &reply_msg.hdr))
+ {
+ success = true;
+ }
+ else
+ {
+ Log * log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ if (log)
+ log->Printf ("mach_exc_server returned zero...");
+ }
+ g_message = NULL;
+ return success;
+}
+
+
+
+kern_return_t
+MachException::Message::Reply(task_t task, pid_t pid, int signal)
+{
+ // Reply to the exception...
+ Error err;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet();
+ if (log)
+ log->Printf("MachException::Message::Reply (task = 0x%4.4x, pid = %i, signal = %i)", task, pid, signal);
+
+ // If we had a soft signal, we need to update the thread first so it can
+ // continue without signaling
+ int soft_signal = state.SoftSignal();
+ int state_pid = LLDB_INVALID_PROCESS_ID;
+ if (task == state.task_port)
+ {
+ // This is our task, so we can update the signal to send to it
+ state_pid = pid;
+ }
+ else
+ {
+ err = ::pid_for_task(state.task_port, &state_pid);
+ }
+
+ if (signal == LLDB_INVALID_SIGNAL_NUMBER)
+ signal = 0;
+
+ if (log)
+ log->Printf("MachException::Message::Reply () updating thread signal to %i (original soft_signal = %i)", signal, soft_signal);
+
+ if (state_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ errno = 0;
+ if (::ptrace (PT_THUPDATE, state_pid, (caddr_t)state.thread_port, signal) != 0)
+ {
+ if (soft_signal != LLDB_INVALID_SIGNAL_NUMBER)
+ // We know we currently can't forward signals for threads that didn't stop in EXC_SOFT_SIGNAL...
+ // So only report it as an error if we should have been able to do it.
+ err.SetErrorToErrno();
+ else
+ err.Clear();
+ }
+ else
+ err.Clear();
+
+ if (log && log->GetMask().IsSet(PD_LOG_EXCEPTIONS) || err.Fail())
+ err.PutToLog(log, "::ptrace (request = PT_THUPDATE, pid = %i, tid = 0x%4.4x, signal = %i)", state_pid, state.thread_port, signal);
+ }
+
+ err = ::mach_msg ( &reply_msg.hdr,
+ MACH_SEND_MSG | MACH_SEND_INTERRUPT,
+ reply_msg.hdr.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ if (log)
+ log->LogIf (PD_LOG_EXCEPTIONS, "::mach_msg ( msg->{bits = %#x, size = %u, remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x) = 0x%8.8x",
+ reply_msg.hdr.msgh_bits,
+ reply_msg.hdr.msgh_size,
+ reply_msg.hdr.msgh_remote_port,
+ reply_msg.hdr.msgh_local_port,
+ reply_msg.hdr.msgh_reserved,
+ reply_msg.hdr.msgh_id,
+ MACH_SEND_MSG | MACH_SEND_INTERRUPT,
+ reply_msg.hdr.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL,
+ err.GetError());
+
+
+ if (err.Fail())
+ {
+ if (err.GetError() == MACH_SEND_INTERRUPTED)
+ {
+ err.PutToLog(log, "::mach_msg() - send interrupted");
+ }
+ else
+ {
+ if (state.task_port == task)
+ {
+ err.PutToLog(log, "::mach_msg() - failed (task)");
+ abort ();
+ }
+ else
+ {
+ err.PutToLog(log, "::mach_msg() - failed (child of task)");
+ }
+ }
+ }
+
+ return err.GetError();
+}
+
+
+void
+MachException::Data::PutToLog(Log *log) const
+{
+ if (log == NULL)
+ return;
+
+ const char *exc_type_name = MachException::Name(exc_type);
+
+ log->Printf (" state { task_port = 0x%4.4x, thread_port = 0x%4.4x, exc_type = %i (%s) ...", task_port, thread_port, exc_type, exc_type_name ? exc_type_name : "???");
+
+ const size_t exc_data_count = exc_data.size();
+ // Dump any special exception data contents
+ int soft_signal = SoftSignal();
+ if (soft_signal > 0)
+ {
+ const char *sig_str = Host::GetSignalAsCString(soft_signal);
+ log->Printf (" exc_data: EXC_SOFT_SIGNAL (%i (%s))", soft_signal, sig_str ? sig_str : "unknown signal");
+ }
+ else
+ {
+ // No special disassembly for this data, just dump the data
+ size_t idx;
+ for (idx = 0; idx < exc_data_count; ++idx)
+ {
+ log->Printf(" exc_data[%u]: " MACH_EXCEPTION_DATA_FMT_HEX, idx, exc_data[idx]);
+ }
+ }
+}
+
+
+MachException::PortInfo::PortInfo() :
+ count(0)
+{
+ ::bzero (masks, sizeof(masks));
+ ::bzero (ports, sizeof(ports));
+ ::bzero (behaviors, sizeof(behaviors));
+ ::bzero (flavors, sizeof(flavors));
+}
+
+
+kern_return_t
+MachException::PortInfo::Save (task_t task)
+{
+ count = EXC_TYPES_COUNT;
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
+ if (log)
+ log->Printf ("MachException::PortInfo::Save (task = 0x%4.4x)", task);
+ Error err;
+ if (log)
+ log->Printf("::task_get_exception_ports (task=0x%4.4x, mask=0x%x, maskCnt<=>%u, ports, behaviors, flavors)...", task, EXC_MASK_ALL, count);
+ err = ::task_get_exception_ports (task, EXC_MASK_ALL, masks, &count, ports, behaviors, flavors);
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_get_exception_ports (task=0x%4.4x, mask=0x%x, maskCnt<=>%u, ports, behaviors, flavors)", task, EXC_MASK_ALL, count);
+ if (log)
+ {
+ mach_msg_type_number_t i;
+ log->Printf("Index Mask Port Behavior Flavor", masks[i], ports[i], behaviors[i], flavors[i]);
+ log->Printf("===== -------- -------- -------- --------");
+ for (i=0; i<count; ++i)
+ log->Printf("[%3u] %8.8x %8.8x %8.8x %8.8x", i, masks[i], ports[i], behaviors[i], flavors[i]);
+ }
+ if (err.Fail())
+ count = 0;
+ return err.GetError();
+}
+
+kern_return_t
+MachException::PortInfo::Restore (task_t task)
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf("MachException::PortInfo::Restore (task = 0x%4.4x)", task);
+ uint32_t i = 0;
+ Error err;
+ if (count > 0)
+ {
+ for (i = 0; i < count; i++)
+ {
+ err = ::task_set_exception_ports (task, masks[i], ports[i], behaviors[i], flavors[i]);
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_set_exception_ports ( task = 0x%4.4x, exception_mask = 0x%8.8x, new_port = 0x%4.4x, behavior = 0x%8.8x, new_flavor = 0x%8.8x )", task, masks[i], ports[i], behaviors[i], flavors[i]);
+
+ if (err.Fail())
+ break;
+ }
+ }
+ count = 0;
+ return err.GetError();
+}
+
+const char *
+MachException::Name(exception_type_t exc_type)
+{
+ switch (exc_type)
+ {
+ case EXC_BAD_ACCESS: return "EXC_BAD_ACCESS";
+ case EXC_BAD_INSTRUCTION: return "EXC_BAD_INSTRUCTION";
+ case EXC_ARITHMETIC: return "EXC_ARITHMETIC";
+ case EXC_EMULATION: return "EXC_EMULATION";
+ case EXC_SOFTWARE: return "EXC_SOFTWARE";
+ case EXC_BREAKPOINT: return "EXC_BREAKPOINT";
+ case EXC_SYSCALL: return "EXC_SYSCALL";
+ case EXC_MACH_SYSCALL: return "EXC_MACH_SYSCALL";
+ case EXC_RPC_ALERT: return "EXC_RPC_ALERT";
+#ifdef EXC_CRASH
+ case EXC_CRASH: return "EXC_CRASH";
+#endif
+ default:
+ break;
+ }
+ return NULL;
+}
+
+
+
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.h b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.h
new file mode 100644
index 00000000000..1f3aeb07b0a
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachException.h
@@ -0,0 +1,148 @@
+//===-- MachException.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef liblldb_MachException_h_
+#define liblldb_MachException_h_
+
+#include <mach/mach.h>
+#include <vector>
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Thread.h"
+// TODO: Get the config script to run to this plug-in
+//#include "PDConfig.h"
+#define HAVE_64_BIT_MACH_EXCEPTIONS // REMOVE THIS WHEN PDConfig.h is included above
+#ifdef HAVE_64_BIT_MACH_EXCEPTIONS
+
+#define MACH_EXCEPTION_DATA_FMT_DEC "%lld"
+#define MACH_EXCEPTION_DATA_FMT_HEX "0x%16.16llx"
+#define MACH_EXCEPTION_DATA_FMT_MINHEX "0x%llx"
+
+#else
+
+#define MACH_EXCEPTION_DATA_FMT_DEC "%d"
+#define MACH_EXCEPTION_DATA_FMT_HEX "0x%8.8x"
+#define MACH_EXCEPTION_DATA_FMT_MINHEX "0x%x"
+
+#endif
+
+class MachProcess;
+
+typedef union MachMessageTag
+{
+ mach_msg_header_t hdr;
+ char data[1024];
+} MachMessage;
+
+
+class MachException
+{
+public:
+
+ struct PortInfo
+ {
+ exception_mask_t masks[EXC_TYPES_COUNT];
+ mach_port_t ports[EXC_TYPES_COUNT];
+ exception_behavior_t behaviors[EXC_TYPES_COUNT];
+ thread_state_flavor_t flavors[EXC_TYPES_COUNT];
+ mach_msg_type_number_t count;
+
+ PortInfo();
+ kern_return_t Save(task_t task);
+ kern_return_t Restore(task_t task);
+ };
+
+ struct Data
+ {
+ task_t task_port;
+ lldb::tid_t thread_port;
+ exception_type_t exc_type;
+ std::vector<mach_exception_data_type_t> exc_data;
+ Data() :
+ task_port(TASK_NULL),
+ thread_port(THREAD_NULL),
+ exc_type(0),
+ exc_data()
+ {
+ }
+
+ void Clear()
+ {
+ task_port = TASK_NULL;
+ thread_port = THREAD_NULL;
+ exc_type = 0;
+ exc_data.clear();
+ }
+ bool IsValid() const
+ {
+ return task_port != TASK_NULL &&
+ thread_port != THREAD_NULL &&
+ exc_type != 0;
+ }
+ // Return the SoftSignal for this MachException data, or zero if there is none
+ int SoftSignal() const
+ {
+ if (exc_type == EXC_SOFTWARE && exc_data.size() == 2 && exc_data[0] == EXC_SOFT_SIGNAL)
+ return exc_data[1];
+ return LLDB_INVALID_SIGNAL_NUMBER;
+ }
+ bool IsBreakpoint() const
+ {
+ return (exc_type == EXC_BREAKPOINT) || ((exc_type == EXC_SOFTWARE) && exc_data[0] == 1);
+ }
+ void PutToLog(lldb_private::Log *log) const;
+ void DumpStopReason() const;
+ bool GetStopInfo(lldb_private::Thread::StopInfo *stop_info) const;
+ };
+
+ struct Message
+ {
+ MachMessage exc_msg;
+ MachMessage reply_msg;
+ Data state;
+
+ Message() :
+ exc_msg(),
+ reply_msg(),
+ state()
+ {
+ memset(&exc_msg, 0, sizeof(exc_msg));
+ memset(&reply_msg, 0, sizeof(reply_msg));
+ }
+ bool CatchExceptionRaise();
+ void PutToLog(lldb_private::Log *log) const;
+ kern_return_t Reply (task_t task, pid_t pid, int signal);
+ kern_return_t Receive( mach_port_t receive_port,
+ mach_msg_option_t options,
+ mach_msg_timeout_t timeout,
+ mach_port_t notify_port = MACH_PORT_NULL);
+
+ typedef std::vector<Message> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ };
+
+ enum
+ {
+ e_actionForward, // Forward signal to inferior process
+ e_actionStop, // Stop when this signal is received
+ };
+ struct Action
+ {
+ task_t task_port; // Set to TASK_NULL for any TASK
+ lldb::tid_t thread_port; // Set to THREAD_NULL for any thread
+ exception_type_t exc_mask; // Mach exception mask to watch for
+ std::vector<mach_exception_data_type_t> exc_data_mask; // Mask to apply to exception data, or empty to ignore exc_data value for exception
+ std::vector<mach_exception_data_type_t> exc_data_value; // Value to compare to exception data after masking, or empty to ignore exc_data value for exception
+ uint8_t flags; // Action flags describing what to do with the exception
+ };
+ static const char *Name(exception_type_t exc_type);
+};
+
+#endif
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.cpp
new file mode 100644
index 00000000000..1a0c3c48997
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.cpp
@@ -0,0 +1,674 @@
+//===-- MachTask.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachTask.h"
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+#if defined (__arm__)
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <SpringBoardServices/SpringBoardServer.h>
+#include <SpringBoardServices/SBSWatchdogAssertion.h>
+
+#endif
+
+#include "lldb/Host/Host.h"
+#include "lldb/Core/DataExtractor.h"
+
+// Project includes
+#include "ProcessMacOSX.h"
+#include "ProcessMacOSXLog.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// MachTask constructor
+//----------------------------------------------------------------------
+MachTask::MachTask(ProcessMacOSX *process) :
+ m_process (process),
+ m_task (TASK_NULL),
+ m_vm_memory (),
+ m_exception_thread (0),
+ m_exception_port (MACH_PORT_NULL),
+ m_exc_port_info()
+{
+ memset(&m_exc_port_info, 0, sizeof(m_exc_port_info));
+
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+MachTask::~MachTask()
+{
+ Clear();
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::Suspend
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::Suspend()
+{
+ Error err;
+ task_t task = GetTaskPort();
+ err = ::task_suspend (task);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_TASK);
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_suspend ( target_task = 0x%4.4x )", task);
+ return err.GetError();
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::Resume
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::Resume()
+{
+ Error err;
+ task_t task = GetTaskPort();
+ err = ::task_resume (task);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_TASK);
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_resume ( target_task = 0x%4.4x )", task);
+ return err.GetError();
+}
+
+int32_t
+MachTask::GetSuspendCount () const
+{
+ struct task_basic_info task_info;
+ if (BasicInfo(&task_info) == KERN_SUCCESS)
+ return task_info.suspend_count;
+ return -1;
+}
+
+//----------------------------------------------------------------------
+// MachTask::ExceptionPort
+//----------------------------------------------------------------------
+mach_port_t
+MachTask::ExceptionPort() const
+{
+ return m_exception_port;
+}
+
+//----------------------------------------------------------------------
+// MachTask::ExceptionPortIsValid
+//----------------------------------------------------------------------
+bool
+MachTask::ExceptionPortIsValid() const
+{
+ return MACH_PORT_VALID(m_exception_port);
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::Clear
+//----------------------------------------------------------------------
+void
+MachTask::Clear()
+{
+ // Do any cleanup needed for this task
+ m_task = TASK_NULL;
+ m_exception_thread = 0;
+ m_exception_port = MACH_PORT_NULL;
+
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::SaveExceptionPortInfo
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::SaveExceptionPortInfo()
+{
+ return m_exc_port_info.Save(GetTaskPort());
+}
+
+//----------------------------------------------------------------------
+// MachTask::RestoreExceptionPortInfo
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::RestoreExceptionPortInfo()
+{
+ return m_exc_port_info.Restore(GetTaskPort());
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::ReadMemory
+//----------------------------------------------------------------------
+size_t
+MachTask::ReadMemory (lldb::addr_t addr, void *buf, size_t size, Error& error)
+{
+ size_t n = 0;
+ task_t task = GetTaskPort();
+ if (task != TASK_NULL)
+ {
+ n = m_vm_memory.Read(task, addr, buf, size, error);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY);
+ if (log)
+ {
+ log->Printf ("MachTask::ReadMemory ( addr = 0x%16.16llx, size = %zu, buf = %8.8p) => %u bytes read", (uint64_t)addr, size, buf, n);
+ if (log->GetMask().IsSet(PD_LOG_MEMORY_DATA_LONG) || (log->GetMask().IsSet(PD_LOG_MEMORY_DATA_SHORT) && size <= 8))
+ {
+ DataExtractor data((uint8_t*)buf, n, eByteOrderHost, 4);
+ data.PutToLog(log, 0, n, addr, 16, DataExtractor::TypeUInt8);
+ }
+ }
+ }
+ return n;
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::WriteMemory
+//----------------------------------------------------------------------
+size_t
+MachTask::WriteMemory (lldb::addr_t addr, const void *buf, size_t size, Error& error)
+{
+ size_t n = 0;
+ task_t task = GetTaskPort();
+ if (task != TASK_NULL)
+ {
+ n = m_vm_memory.Write(task, addr, buf, size, error);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY);
+ if (log)
+ {
+ log->Printf ("MachTask::WriteMemory ( addr = 0x%16.16llx, size = %zu, buf = %8.8p) => %u bytes written", (uint64_t)addr, size, buf, n);
+ if (log->GetMask().IsSet(PD_LOG_MEMORY_DATA_LONG) || (log->GetMask().IsSet(PD_LOG_MEMORY_DATA_SHORT) && size <= 8))
+ {
+ DataExtractor data((uint8_t*)buf, n, eByteOrderHost, 4);
+ data.PutToLog(log, 0, n, addr, 16, DataExtractor::TypeUInt8);
+ }
+ }
+ }
+ return n;
+}
+
+//----------------------------------------------------------------------
+// MachTask::AllocateMemory
+//----------------------------------------------------------------------
+lldb::addr_t
+MachTask::AllocateMemory (size_t size, uint32_t permissions, Error& error)
+{
+ // FIXME: vm_allocate allocates a page at a time, so we should use
+ // host_page_size to get the host page size and then parcel out the
+ // page we get back until it is filled.
+ // FIXME: Add log messages.
+
+ kern_return_t kret;
+ mach_vm_address_t addr;
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY);
+
+ kret = ::mach_vm_allocate (GetTaskPort(), &addr, size, TRUE);
+ if (kret == KERN_SUCCESS)
+ {
+ // Set the protections:
+ vm_prot_t mach_prot = 0;
+ if (permissions & lldb::ePermissionsReadable)
+ mach_prot |= VM_PROT_READ;
+ if (permissions & lldb::ePermissionsWritable)
+ mach_prot |= VM_PROT_WRITE;
+ if (permissions & lldb::ePermissionsExecutable)
+ mach_prot |= VM_PROT_EXECUTE;
+
+ kret = ::mach_vm_protect (GetTaskPort(), addr, size, 0, mach_prot);
+ if (kret == KERN_SUCCESS)
+ {
+ if (log)
+ log->Printf("Allocated memory at addr = 0x%16.16llx, size = %zu, prot = 0x%x)", (uint64_t) addr, size, mach_prot);
+ m_allocations.insert (std::make_pair(addr, size));
+ return (lldb::addr_t) addr;
+ }
+ else
+ {
+ if (log)
+ log->Printf("Failed to set protections on memory at addr = 0x%16.16llx, size = %zu), prot = 0x%x", (uint64_t) addr, size, mach_prot);
+ kret = ::mach_vm_deallocate (GetTaskPort(), addr, size);
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("Failed to set allocate memory: size = %zu)", size);
+ return LLDB_INVALID_ADDRESS;
+ }
+}
+
+//----------------------------------------------------------------------
+// MachTask::DeallocateMemory
+//----------------------------------------------------------------------
+Error
+MachTask::DeallocateMemory (lldb::addr_t ptr)
+{
+ Error error;
+ // We have to stash away sizes for the allocations...
+ allocation_collection::iterator pos, end = m_allocations.end();
+ for (pos = m_allocations.begin(); pos != end; pos++)
+ {
+ if ((*pos).first == ptr)
+ {
+ m_allocations.erase (pos);
+ error = ::mach_vm_deallocate (GetTaskPort(), (vm_address_t) ptr, (*pos).second);
+ return error;
+ }
+ }
+ error.SetErrorStringWithFormat("no memory allocated at 0x%llx", (uint64_t)ptr);
+ return error;
+}
+
+//----------------------------------------------------------------------
+// MachTask::TaskPortForProcessID
+//----------------------------------------------------------------------
+task_t
+MachTask::GetTaskPortForProcessID (Error &err)
+{
+ err.Clear();
+ if (m_task == TASK_NULL && m_process != NULL)
+ m_task = MachTask::GetTaskPortForProcessID(m_process->GetID(), err);
+ return m_task;
+}
+
+//----------------------------------------------------------------------
+// MachTask::TaskPortForProcessID
+//----------------------------------------------------------------------
+task_t
+MachTask::GetTaskPortForProcessID (lldb::pid_t pid, Error &err)
+{
+ task_t task = TASK_NULL;
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ mach_port_t task_self = mach_task_self ();
+ err = ::task_for_pid ( task_self, pid, &task);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_TASK);
+ if (log || err.Fail())
+ {
+ err.PutToLog(log, "::task_for_pid ( target_tport = 0x%4.4x, pid = %d, task => 0x%4.4x ) %u/%u %u/%u", task_self, pid, task, getuid(), geteuid(), getgid(), getegid());
+ }
+ }
+ return task;
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::BasicInfo
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::BasicInfo(struct task_basic_info *info) const
+{
+ return BasicInfo (GetTaskPort(), info);
+}
+
+//----------------------------------------------------------------------
+// MachTask::BasicInfo
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::BasicInfo(task_t task, struct task_basic_info *info)
+{
+ if (info == NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ Error err;
+ mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
+ err = ::task_info (task, TASK_BASIC_INFO, (task_info_t)info, &count);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_TASK);
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_info ( target_task = 0x%4.4x, flavor = TASK_BASIC_INFO, task_info_out => %p, task_info_outCnt => %u )", task, info, count);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE) && err.Success())
+ {
+ float user = (float)info->user_time.seconds + (float)info->user_time.microseconds / 1000000.0f;
+ float system = (float)info->user_time.seconds + (float)info->user_time.microseconds / 1000000.0f;
+ log->Printf ("task_basic_info = { suspend_count = %i, virtual_size = 0x%8.8x, resident_size = 0x%8.8x, user_time = %f, system_time = %f }",
+ info->suspend_count, info->virtual_size, info->resident_size, user, system);
+ }
+ return err.GetError();
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::IsValid
+//
+// Returns true if a task is a valid task port for a current process.
+//----------------------------------------------------------------------
+bool
+MachTask::IsValid () const
+{
+ return MachTask::IsValid(GetTaskPort());
+}
+
+//----------------------------------------------------------------------
+// MachTask::IsValid
+//
+// Returns true if a task is a valid task port for a current process.
+//----------------------------------------------------------------------
+bool
+MachTask::IsValid (task_t task)
+{
+ if (task != TASK_NULL)
+ {
+ struct task_basic_info task_info;
+ return BasicInfo(task, &task_info) == KERN_SUCCESS;
+ }
+ return false;
+}
+
+
+bool
+MachTask::StartExceptionThread(Error &err)
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
+
+ if (log)
+ log->Printf ("MachTask::%s ( )", __FUNCTION__);
+ task_t task = GetTaskPortForProcessID(err);
+ if (MachTask::IsValid(task))
+ {
+ // Got the mach port for the current process
+ mach_port_t task_self = mach_task_self ();
+
+ // Allocate an exception port that we will use to track our child process
+ err = ::mach_port_allocate (task_self, MACH_PORT_RIGHT_RECEIVE, &m_exception_port);
+ if (log || err.Fail())
+ err.PutToLog(log, "::mach_port_allocate (task_self=0x%4.4x, MACH_PORT_RIGHT_RECEIVE, &m_exception_port => 0x%4.4x)",
+ task_self, m_exception_port);
+ if (err.Fail())
+ return false;
+
+ // Add the ability to send messages on the new exception port
+ err = ::mach_port_insert_right (task_self, m_exception_port, m_exception_port, MACH_MSG_TYPE_MAKE_SEND);
+ if (log || err.Fail())
+ err.PutToLog(log, "::mach_port_insert_right (task_self=0x%4.4x, m_exception_port=0x%4.4x, m_exception_port=0x%4.4x, MACH_MSG_TYPE_MAKE_SEND)",
+ task_self, m_exception_port, m_exception_port);
+ if (err.Fail())
+ return false;
+
+ // Save the original state of the exception ports for our child process
+ err = SaveExceptionPortInfo();
+
+ // Set the ability to get all exceptions on this port
+ err = ::task_set_exception_ports (task, EXC_MASK_ALL, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_set_exception_ports (task, EXC_MASK_ALL, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE)");
+ if (err.Fail())
+ return false;
+
+ // Create the exception thread
+ char thread_name[256];
+ ::snprintf (thread_name, sizeof(thread_name), "<lldb.process.process-macosx.mach-exception-%d>", m_process->GetID());
+ m_exception_thread = Host::ThreadCreate (thread_name, MachTask::ExceptionThread, this, &err);
+
+ return err.Success();
+ }
+ return false;
+}
+
+kern_return_t
+MachTask::ShutDownExceptionThread()
+{
+ Error err;
+
+ if (m_exception_thread == NULL)
+ return KERN_SUCCESS;
+
+ err = RestoreExceptionPortInfo();
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
+
+ // NULL our our exception port and let our exception thread exit
+ mach_port_t exception_port = m_exception_port;
+ m_exception_port = NULL;
+
+ Host::ThreadCancel (m_exception_thread, &err);
+ if (log || err.Fail())
+ err.PutToLog(log, "Host::ThreadCancel ( thread = %p )", m_exception_thread);
+
+ Host::ThreadJoin (m_exception_thread, NULL, &err);
+ if (log || err.Fail())
+ err.PutToLog(log, "Host::ThreadJoin ( thread = %p, result_ptr = NULL)", m_exception_thread);
+
+ // Deallocate our exception port that we used to track our child process
+ mach_port_t task_self = mach_task_self ();
+ err = ::mach_port_deallocate (task_self, exception_port);
+ if (log || err.Fail())
+ err.PutToLog(log, "::mach_port_deallocate ( task = 0x%4.4x, name = 0x%4.4x )", task_self, exception_port);
+ exception_port = NULL;
+
+ Clear();
+ return err.GetError();
+}
+
+
+void *
+MachTask::ExceptionThread (void *arg)
+{
+ if (arg == NULL)
+ return NULL;
+
+ MachTask *mach_task = (MachTask*) arg;
+ ProcessMacOSX *mach_proc = mach_task->Process();
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
+ if (log)
+ log->Printf ("MachTask::%s (arg = %p) thread starting...", __FUNCTION__, arg);
+
+ // We keep a count of the number of consecutive exceptions received so
+ // we know to grab all exceptions without a timeout. We do this to get a
+ // bunch of related exceptions on our exception port so we can process
+ // then together. When we have multiple threads, we can get an exception
+ // per thread and they will come in consecutively. The main loop in this
+ // thread can stop periodically if needed to service things related to this
+ // process.
+ // flag set in the options, so we will wait forever for an exception on
+ // our exception port. After we get one exception, we then will use the
+ // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current
+ // exceptions for our process. After we have received the last pending
+ // exception, we will get a timeout which enables us to then notify
+ // our main thread that we have an exception bundle avaiable. We then wait
+ // for the main thread to tell this exception thread to start trying to get
+ // exceptions messages again and we start again with a mach_msg read with
+ // infinite timeout.
+ uint32_t num_exceptions_received = 0;
+ Error err;
+ task_t task = mach_task->GetTaskPort();
+ mach_msg_timeout_t periodic_timeout = 1000;
+
+#if defined (__arm__)
+ mach_msg_timeout_t watchdog_elapsed = 0;
+ mach_msg_timeout_t watchdog_timeout = 60 * 1000;
+ lldb::pid_t pid = mach_proc->GetID();
+ CFReleaser<SBSWatchdogAssertionRef> watchdog;
+
+ if (mach_proc->ProcessUsingSpringBoard())
+ {
+ // Request a renewal for every 60 seconds if we attached using SpringBoard
+ watchdog.reset(::SBSWatchdogAssertionCreateForPID(NULL, pid, 60));
+ if (log)
+ log->Printf ("::SBSWatchdogAssertionCreateForPID (NULL, %4.4x, 60 ) => %p", pid, watchdog.get());
+
+ if (watchdog.get())
+ {
+ ::SBSWatchdogAssertionRenew (watchdog.get());
+
+ CFTimeInterval watchdogRenewalInterval = ::SBSWatchdogAssertionGetRenewalInterval (watchdog.get());
+ if (log)
+ log->Printf ("::SBSWatchdogAssertionGetRenewalInterval ( %p ) => %g seconds", watchdog.get(), watchdogRenewalInterval);
+ if (watchdogRenewalInterval > 0.0)
+ {
+ watchdog_timeout = (mach_msg_timeout_t)watchdogRenewalInterval * 1000;
+ if (watchdog_timeout > 3000)
+ watchdog_timeout -= 1000; // Give us a second to renew our timeout
+ else if (watchdog_timeout > 1000)
+ watchdog_timeout -= 250; // Give us a quarter of a second to renew our timeout
+ }
+ }
+ if (periodic_timeout == 0 || periodic_timeout > watchdog_timeout)
+ periodic_timeout = watchdog_timeout;
+ }
+#endif // #if defined (__arm__)
+
+ while (mach_task->ExceptionPortIsValid())
+ {
+ //::pthread_testcancel ();
+
+ MachException::Message exception_message;
+
+
+ if (num_exceptions_received > 0)
+ {
+ // No timeout, just receive as many exceptions as we can since we already have one and we want
+ // to get all currently available exceptions for this task
+ err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, 0);
+ }
+ else if (periodic_timeout > 0)
+ {
+ // We need to stop periodically in this loop, so try and get a mach message with a valid timeout (ms)
+ err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, periodic_timeout);
+ }
+ else
+ {
+ // We don't need to parse all current exceptions or stop periodically,
+ // just wait for an exception forever.
+ err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0);
+ }
+
+ if (err.GetError() == MACH_RCV_INTERRUPTED)
+ {
+ // If we have no task port we should exit this thread
+ if (!mach_task->ExceptionPortIsValid())
+ {
+ if (log)
+ log->Printf ("thread cancelled...");
+ break;
+ }
+
+ // Make sure our task is still valid
+ if (MachTask::IsValid(task))
+ {
+ // Task is still ok
+ if (log)
+ log->Printf ("interrupted, but task still valid, continuing...");
+ continue;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("task has exited...");
+ mach_proc->SetPrivateState (eStateExited);
+ // Our task has died, exit the thread.
+ break;
+ }
+ }
+ else if (err.GetError() == MACH_RCV_TIMED_OUT)
+ {
+ if (num_exceptions_received > 0)
+ {
+ // We were receiving all current exceptions with a timeout of zero
+ // it is time to go back to our normal looping mode
+ num_exceptions_received = 0;
+
+ // Notify our main thread we have a complete exception message
+ // bundle available.
+ mach_proc->ExceptionMessageBundleComplete();
+
+ // in case we use a timeout value when getting exceptions...
+ // Make sure our task is still valid
+ if (MachTask::IsValid(task))
+ {
+ // Task is still ok
+ if (log)
+ log->Printf ("got a timeout, continuing...");
+ continue;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("task has exited...");
+ mach_proc->SetPrivateState (eStateExited);
+ // Our task has died, exit the thread.
+ break;
+ }
+ continue;
+ }
+
+#if defined (__arm__)
+ if (watchdog.get())
+ {
+ watchdog_elapsed += periodic_timeout;
+ if (watchdog_elapsed >= watchdog_timeout)
+ {
+ LogIf(PD_LOG_TASK, "SBSWatchdogAssertionRenew ( %p )", watchdog.get());
+ ::SBSWatchdogAssertionRenew (watchdog.get());
+ watchdog_elapsed = 0;
+ }
+ }
+#endif
+ }
+ else if (err.GetError() != KERN_SUCCESS)
+ {
+ if (log)
+ log->Printf ("got some other error, do something about it??? nah, continuing for now...");
+ // TODO: notify of error?
+ }
+ else
+ {
+ if (exception_message.CatchExceptionRaise())
+ {
+ ++num_exceptions_received;
+ mach_proc->ExceptionMessageReceived(exception_message);
+ }
+ }
+ }
+
+#if defined (__arm__)
+ if (watchdog.get())
+ {
+ // TODO: change SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel when we
+ // all are up and running on systems that support it. The SBS framework has a #define
+ // that will forward SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel for now
+ // so it should still build either way.
+ LogIf(PD_LOG_TASK, "::SBSWatchdogAssertionRelease(%p)", watchdog.get());
+ ::SBSWatchdogAssertionRelease (watchdog.get());
+ }
+#endif // #if defined (__arm__)
+
+ if (log)
+ log->Printf ("MachTask::%s (arg = %p) thread exiting...", __FUNCTION__, arg);
+ return NULL;
+}
+
+lldb::addr_t
+MachTask::GetDYLDAllImageInfosAddress ()
+{
+#ifdef TASK_DYLD_INFO
+ task_dyld_info_data_t dyld_info;
+ mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+ Error err;
+ // The actual task shouldn't matter for the DYLD info, so lets just use ours
+ kern_return_t kret = ::task_info (GetTaskPortForProcessID (err), TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
+ if (kret == KERN_SUCCESS)
+ {
+ // We now have the address of the all image infos structure
+ return dyld_info.all_image_info_addr;
+ }
+#endif
+ return LLDB_INVALID_ADDRESS;
+}
+
+
+
+
+
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.h b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.h
new file mode 100644
index 00000000000..228cb7c516b
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachTask.h
@@ -0,0 +1,138 @@
+//===-- MachTask.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __MachTask_h__
+#define __MachTask_h__
+
+// C Includes
+// C++ Includes
+#include <map>
+// Other libraries and framework includes
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <sys/socket.h>
+
+// Project includes
+#include "MachException.h"
+#include "MachVMMemory.h"
+
+class ProcessMacOSX;
+
+class MachTask
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ MachTask (ProcessMacOSX *process);
+
+ virtual
+ ~MachTask ();
+
+ void
+ Clear ();
+
+ kern_return_t
+ Suspend ();
+
+ kern_return_t
+ Resume ();
+
+ int32_t
+ GetSuspendCount () const;
+
+ size_t
+ ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error& error);
+
+ size_t
+ WriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error& error);
+
+ lldb::addr_t
+ AllocateMemory (size_t size, uint32_t permissions, lldb_private::Error& error);
+
+ lldb_private::Error
+ DeallocateMemory (lldb::addr_t addr);
+
+ mach_port_t
+ ExceptionPort () const;
+
+ bool
+ ExceptionPortIsValid () const;
+
+ kern_return_t
+ SaveExceptionPortInfo ();
+
+ kern_return_t
+ RestoreExceptionPortInfo ();
+
+ kern_return_t
+ ShutDownExceptionThread ();
+
+ bool
+ StartExceptionThread (lldb_private::Error &err);
+
+ lldb::addr_t
+ GetDYLDAllImageInfosAddress ();
+
+ kern_return_t
+ BasicInfo (struct task_basic_info *info) const;
+
+ static kern_return_t
+ BasicInfo (task_t task, struct task_basic_info *info);
+
+ bool
+ IsValid () const;
+
+ static bool
+ IsValid (task_t task);
+
+ static void *
+ ExceptionThread (void *arg);
+
+ task_t
+ GetTaskPort () const
+ {
+ return m_task;
+ }
+
+ task_t
+ GetTaskPortForProcessID (lldb_private::Error &err);
+
+ static task_t
+ GetTaskPortForProcessID (lldb::pid_t pid, lldb_private::Error &err);
+
+ ProcessMacOSX *
+ Process ()
+ {
+ return m_process;
+ }
+
+ const ProcessMacOSX *
+ Process () const
+ {
+ return m_process;
+ }
+
+protected:
+ ProcessMacOSX * m_process; // The mach process that owns this MachTask
+ task_t m_task;
+ MachVMMemory m_vm_memory; // Special mach memory reading class that will take care of watching for page and region boundaries
+ MachException::PortInfo m_exc_port_info; // Saved settings for all exception ports
+ lldb::thread_t m_exception_thread; // Thread ID for the exception thread in case we need it
+ mach_port_t m_exception_port; // Exception port on which we will receive child exceptions
+
+ // Maybe sort this by address and use find?
+ typedef std::map<vm_address_t,size_t> allocation_collection;
+ allocation_collection m_allocations;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (MachTask);
+};
+
+#endif // __MachTask_h__
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext.h b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext.h
new file mode 100644
index 00000000000..3166c2802f3
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext.h
@@ -0,0 +1,48 @@
+//===-- MachThreadContext.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MachThreadContext_h_
+#define liblldb_MachThreadContext_h_
+
+#include <vector>
+
+#include "MachException.h"
+
+class ThreadMacOSX;
+
+class MachThreadContext
+{
+public:
+ MachThreadContext (ThreadMacOSX &thread) :
+ m_thread (thread)
+ {
+ }
+
+ virtual ~MachThreadContext()
+ {
+ }
+
+ virtual lldb_private::RegisterContext *
+ CreateRegisterContext (lldb_private::StackFrame *frame) const = 0;
+
+ virtual void InitializeInstance() = 0;
+ virtual void ThreadWillResume () = 0;
+ virtual bool ShouldStop () = 0;
+ virtual void RefreshStateAfterStop() = 0;
+ virtual bool NotifyException (MachException::Data& exc) { return false; }
+ virtual bool StepNotComplete () { return false; }
+ virtual size_t GetStackFrameData(lldb_private::StackFrame *frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs) { return 0; }
+// virtual const uint8_t * SoftwareBreakpointOpcode (size_t byte_size) = 0;
+
+protected:
+ ThreadMacOSX &m_thread;
+
+};
+
+#endif // #ifndef liblldb_MachThreadContext_h_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.cpp
new file mode 100644
index 00000000000..4f6b17c81a2
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.cpp
@@ -0,0 +1,1884 @@
+//===-- MachThreadContext_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 "MachThreadContext_arm.h"
+
+#include <sys/sysctl.h>
+
+#include "ProcessMacOSX.h"
+#include "ProcessMacOSXLog.h"
+#include "ThreadMacOSX.h"
+
+using namespace lldb_private;
+
+//#define DNB_ARCH_MACH_ARM_DEBUG_SW_STEP 1
+
+static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 };
+static const uint8_t g_thumb_breakpooint_opcode[] = { 0xFE, 0xDE };
+
+// ARM constants used during decoding
+#define REG_RD 0
+#define LDM_REGLIST 1
+#define PC_REG 15
+#define PC_REGLIST_BIT 0x8000
+
+// ARM conditions
+#define COND_EQ 0x0
+#define COND_NE 0x1
+#define COND_CS 0x2
+#define COND_HS 0x2
+#define COND_CC 0x3
+#define COND_LO 0x3
+#define COND_MI 0x4
+#define COND_PL 0x5
+#define COND_VS 0x6
+#define COND_VC 0x7
+#define COND_HI 0x8
+#define COND_LS 0x9
+#define COND_GE 0xA
+#define COND_LT 0xB
+#define COND_GT 0xC
+#define COND_LE 0xD
+#define COND_AL 0xE
+#define COND_UNCOND 0xF
+
+#define MASK_CPSR_T (1u << 5)
+#define MASK_CPSR_J (1u << 24)
+
+#define MNEMONIC_STRING_SIZE 32
+#define OPERAND_STRING_SIZE 128
+
+using namespace lldb;
+using namespace lldb_private;
+
+MachThreadContext_arm::MachThreadContext_arm(ThreadMacOSX &thread) :
+ MachThreadContext(thread),
+ m_hw_single_chained_step_addr(LLDB_INVALID_ADDRESS),
+ m_bvr0_reg (LLDB_INVALID_REGNUM),
+ m_bcr0_reg (LLDB_INVALID_REGNUM),
+ m_bvr0_save (0),
+ m_bcr0_save (0)
+{
+}
+
+MachThreadContext_arm::~MachThreadContext_arm()
+{
+}
+
+RegisterContext *
+MachThreadContext_arm::CreateRegisterContext (StackFrame *frame) const
+{
+ return new RegisterContextMach_arm(m_thread, frame);
+}
+
+// Instance init function
+void
+MachThreadContext_arm::InitializeInstance()
+{
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx != NULL);
+ const RegisterInfo * reg_info;
+ reg_info = reg_ctx->GetRegisterInfoByName ("bvr0");
+ if (reg_info)
+ m_bvr0_reg = reg_info->reg;
+
+ reg_info = reg_ctx->GetRegisterInfoByName ("bcr0");
+ if (reg_info)
+ m_bcr0_reg = reg_info->reg;
+}
+
+
+
+uint32_t
+MachThreadContext_arm::GetCPUType()
+{
+ return CPU_TYPE_ARM;
+}
+
+void
+MachThreadContext_arm::ThreadWillResume()
+{
+ // Do we need to step this thread? If so, let the mach thread tell us so.
+ if (m_thread.GetState() == eStateStepping)
+ {
+ bool step_handled = false;
+ // This is the primary thread, let the arch do anything it needs
+ if (m_thread.GetRegisterContext()->NumSupportedHardwareBreakpoints() > 0)
+ {
+#if defined (DNB_ARCH_MACH_ARM_DEBUG_SW_STEP)
+ bool half_step = m_hw_single_chained_step_addr != LLDB_INVALID_ADDRESS;
+#endif
+ step_handled = EnableHardwareSingleStep(true) == KERN_SUCCESS;
+#if defined (DNB_ARCH_MACH_ARM_DEBUG_SW_STEP)
+ if (!half_step)
+ step_handled = false;
+#endif
+ }
+
+#if defined (ENABLE_ARM_SINGLE_STEP)
+ if (!step_handled)
+ {
+ SetSingleStepSoftwareBreakpoints();
+ }
+#endif
+ }
+}
+
+bool
+MachThreadContext_arm::ShouldStop ()
+{
+ return true;
+}
+
+void
+MachThreadContext_arm::RefreshStateAfterStop ()
+{
+ EnableHardwareSingleStep (false) == KERN_SUCCESS;
+}
+
+#if defined (ENABLE_ARM_SINGLE_STEP)
+
+bool
+MachThreadContext_arm::ShouldStop ()
+{
+ return true;
+}
+
+bool
+MachThreadContext_arm::RefreshStateAfterStop ()
+{
+ success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
+
+ bool success = true;
+
+ m_state.InvalidateRegisterSet (GPRRegSet);
+ m_state.InvalidateRegisterSet (VFPRegSet);
+ m_state.InvalidateRegisterSet (EXCRegSet);
+
+ // Are we stepping a single instruction?
+ if (ReadGPRRegisters(true) == KERN_SUCCESS)
+ {
+ // We are single stepping, was this the primary thread?
+ if (m_thread.GetState() == eStateStepping)
+ {
+#if defined (DNB_ARCH_MACH_ARM_DEBUG_SW_STEP)
+ success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
+ // Hardware single step must work if we are going to test software
+ // single step functionality
+ assert(success);
+ if (m_hw_single_chained_step_addr == LLDB_INVALID_ADDRESS && m_sw_single_step_next_pc != LLDB_INVALID_ADDRESS)
+ {
+ uint32_t sw_step_next_pc = m_sw_single_step_next_pc & 0xFFFFFFFEu;
+ bool sw_step_next_pc_is_thumb = (m_sw_single_step_next_pc & 1) != 0;
+ bool actual_next_pc_is_thumb = (m_state.gpr.__cpsr & 0x20) != 0;
+ if (m_state.gpr.r[15] != sw_step_next_pc)
+ {
+ LogError("curr pc = 0x%8.8x - calculated single step target PC was incorrect: 0x%8.8x != 0x%8.8x", m_state.gpr.r[15], sw_step_next_pc, m_state.gpr.r[15]);
+ exit(1);
+ }
+ if (actual_next_pc_is_thumb != sw_step_next_pc_is_thumb)
+ {
+ LogError("curr pc = 0x%8.8x - calculated single step calculated mode mismatch: sw single mode = %s != %s",
+ m_state.gpr.r[15],
+ actual_next_pc_is_thumb ? "Thumb" : "ARM",
+ sw_step_next_pc_is_thumb ? "Thumb" : "ARM");
+ exit(1);
+ }
+ m_sw_single_step_next_pc = LLDB_INVALID_ADDRESS;
+ }
+#else
+#if defined (ENABLE_ARM_SINGLE_STEP)
+ // Are we software single stepping?
+ if (LLDB_BREAK_ID_IS_VALID(m_sw_single_step_break_id) || m_sw_single_step_itblock_break_count)
+ {
+ // Remove any software single stepping breakpoints that we have set
+
+ // Do we have a normal software single step breakpoint?
+ if (LLDB_BREAK_ID_IS_VALID(m_sw_single_step_break_id))
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: removing software single step breakpoint (breakID=%d)", __FUNCTION__, m_sw_single_step_break_id);
+ success = m_thread.Process()->DisableBreakpoint(m_sw_single_step_break_id, true);
+ m_sw_single_step_break_id = LLDB_INVALID_BREAK_ID;
+ }
+
+ // Do we have any Thumb IT breakpoints?
+ if (m_sw_single_step_itblock_break_count > 0)
+ {
+ // See if we hit one of our Thumb IT breakpoints?
+ DNBBreakpoint *step_bp = m_thread.Process()->Breakpoints().FindByAddress(m_state.gpr.r[15]);
+
+ if (step_bp)
+ {
+ // We did hit our breakpoint, tell the breakpoint it was
+ // hit so that it can run its callback routine and fixup
+ // the PC.
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: IT software single step breakpoint hit (breakID=%u)", __FUNCTION__, step_bp->GetID());
+ step_bp->BreakpointHit(m_thread.Process()->ProcessID(), m_thread.GetID());
+ }
+
+ // Remove all Thumb IT breakpoints
+ for (int i = 0; i < m_sw_single_step_itblock_break_count; i++)
+ {
+ if (LLDB_BREAK_ID_IS_VALID(m_sw_single_step_itblock_break_id[i]))
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: removing IT software single step breakpoint (breakID=%d)", __FUNCTION__, m_sw_single_step_itblock_break_id[i]);
+ success = m_thread.Process()->DisableBreakpoint(m_sw_single_step_itblock_break_id[i], true);
+ m_sw_single_step_itblock_break_id[i] = LLDB_INVALID_BREAK_ID;
+ }
+ }
+ m_sw_single_step_itblock_break_count = 0;
+
+ // Decode instructions up to the current PC to ensure the internal decoder state is valid for the IT block
+ // The decoder has to decode each instruction in the IT block even if it is not executed so that
+ // the fields are correctly updated
+ DecodeITBlockInstructions(m_state.gpr.r[15]);
+ }
+
+ }
+ else
+#endif
+ success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
+#endif
+ }
+ else
+ {
+ // The MachThread will automatically restore the suspend count
+ // in ShouldStop (), so we don't need to do anything here if
+ // we weren't the primary thread the last time
+ }
+ }
+ return;
+}
+
+
+
+bool
+MachThreadContext_arm::StepNotComplete ()
+{
+ if (m_hw_single_chained_step_addr != LLDB_INVALID_ADDRESS)
+ {
+ kern_return_t kret = KERN_INVALID_ARGUMENT;
+ kret = ReadGPRRegisters(false);
+ if (kret == KERN_SUCCESS)
+ {
+ if (m_state.gpr.r[15] == m_hw_single_chained_step_addr)
+ {
+ //ProcessMacOSXLog::LogIf(PD_LOG_STEP, "Need to step some more at 0x%8.8x", m_hw_single_chained_step_addr);
+ return true;
+ }
+ }
+ }
+
+ m_hw_single_chained_step_addr = LLDB_INVALID_ADDRESS;
+ return false;
+}
+
+
+void
+MachThreadContext_arm::DecodeITBlockInstructions(lldb::addr_t curr_pc)
+
+{
+ uint16_t opcode16;
+ uint32_t opcode32;
+ lldb::addr_t next_pc_in_itblock;
+ lldb::addr_t pc_in_itblock = m_last_decode_pc;
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: last_decode_pc=0x%8.8x", __FUNCTION__, m_last_decode_pc);
+
+ // Decode IT block instruction from the instruction following the m_last_decoded_instruction at
+ // PC m_last_decode_pc upto and including the instruction at curr_pc
+ if (m_thread.Process()->Task().ReadMemory(pc_in_itblock, 2, &opcode16) == 2)
+ {
+ opcode32 = opcode16;
+ pc_in_itblock += 2;
+ // Check for 32 bit thumb opcode and read the upper 16 bits if needed
+ if (((opcode32 & 0xE000) == 0xE000) && opcode32 & 0x1800)
+ {
+ // Adjust 'next_pc_in_itblock' to point to the default next Thumb instruction for
+ // a 32 bit Thumb opcode
+ // Read bits 31:16 of a 32 bit Thumb opcode
+ if (m_thread.Process()->Task().ReadMemory(pc_in_itblock, 2, &opcode16) == 2)
+ {
+ pc_in_itblock += 2;
+ // 32 bit thumb opcode
+ opcode32 = (opcode32 << 16) | opcode16;
+ }
+ else
+ {
+ LogError("%s: Unable to read opcode bits 31:16 for a 32 bit thumb opcode at pc=0x%8.8lx", __FUNCTION__, pc_in_itblock);
+ }
+ }
+ }
+ else
+ {
+ LogError("%s: Error reading 16-bit Thumb instruction at pc=0x%8.8x", __FUNCTION__, pc_in_itblock);
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: pc_in_itblock=0x%8.8x, curr_pc=0x%8.8x", __FUNCTION__, pc_in_itblock, curr_pc);
+
+ next_pc_in_itblock = pc_in_itblock;
+ while (next_pc_in_itblock <= curr_pc)
+ {
+ arm_error_t decodeError;
+
+ m_last_decode_pc = pc_in_itblock;
+ decodeError = DecodeInstructionUsingDisassembler(pc_in_itblock, m_state.gpr.__cpsr, &m_last_decode_arm, &m_last_decode_thumb, &next_pc_in_itblock);
+
+ pc_in_itblock = next_pc_in_itblock;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: next_pc_in_itblock=0x%8.8x", __FUNCTION__, next_pc_in_itblock);
+ }
+}
+
+#endif
+
+// Set the single step bit in the processor status register.
+kern_return_t
+MachThreadContext_arm::EnableHardwareSingleStep (bool enable)
+{
+ Error err;
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_STEP);
+
+ if (log) log->Printf("%s( enable = %d )", __FUNCTION__, enable);
+
+ if (m_bvr0_reg == LLDB_INVALID_REGNUM || m_bcr0_reg == LLDB_INVALID_REGNUM)
+ return KERN_INVALID_ARGUMENT;
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ uint32_t bvr = 0;
+ uint32_t bcr = 0;
+
+ const uint32_t i = 0;
+ if (enable)
+ {
+ m_hw_single_chained_step_addr = LLDB_INVALID_ADDRESS;
+
+ // Save our previous state
+ m_bvr0_save = reg_ctx->ReadRegisterAsUnsigned(m_bvr0_reg, 0);
+ m_bcr0_save = reg_ctx->ReadRegisterAsUnsigned(m_bcr0_reg, 0);
+ lldb::addr_t pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
+ lldb::addr_t cpsr = reg_ctx->GetFlags(0);
+ if (pc == LLDB_INVALID_ADDRESS)
+ return KERN_INVALID_ARGUMENT;
+
+ // Set a breakpoint that will stop when the PC doesn't match the current one!
+ bvr = pc & 0xFFFFFFFCu; // Set the current PC as the breakpoint address
+ bcr = BCR_M_IMVA_MISMATCH | // Stop on address mismatch
+ S_USER | // Stop only in user mode
+ BCR_ENABLE; // Enable this breakpoint
+ if (cpsr & 0x20)
+ {
+ // Thumb breakpoint
+ if (pc & 2)
+ bcr |= BAS_IMVA_2_3;
+ else
+ bcr |= BAS_IMVA_0_1;
+
+ uint16_t opcode;
+ Error error;
+ if (sizeof(opcode) == m_thread.GetProcess().ReadMemory(pc, &opcode, sizeof(opcode), error))
+ {
+ if (((opcode & 0xE000) == 0xE000) && opcode & 0x1800)
+ {
+ // 32 bit thumb opcode...
+ if (pc & 2)
+ {
+ // We can't take care of a 32 bit thumb instruction single step
+ // with just IVA mismatching. We will need to chain an extra
+ // hardware single step in order to complete this single step...
+ m_hw_single_chained_step_addr = pc + 2;
+ }
+ else
+ {
+ // Extend the number of bits to ignore for the mismatch
+ bcr |= BAS_IMVA_ALL;
+ }
+ }
+ }
+ }
+ else
+ {
+ // ARM breakpoint
+ bcr |= BAS_IMVA_ALL; // Stop when any address bits change
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: BVR%u=0x%8.8x BCR%u=0x%8.8x", __FUNCTION__, i, bvr, i, bcr);
+
+ m_bvr0_save = reg_ctx->ReadRegisterAsUnsigned(m_bvr0_reg, 0);
+ m_bcr0_save = reg_ctx->ReadRegisterAsUnsigned(m_bcr0_reg, 0);
+
+// for (uint32_t j=i+1; j<16; ++j)
+// {
+// // Disable all others
+// m_state.dbg.bvr[j] = 0;
+// m_state.dbg.bcr[j] = 0;
+// }
+ }
+ else
+ {
+ // Just restore the state we had before we did single stepping
+ bvr = m_bvr0_save;
+ bcr = m_bcr0_save;
+ }
+
+ if (reg_ctx->WriteRegisterFromUnsigned(m_bvr0_reg, bvr) &&
+ reg_ctx->WriteRegisterFromUnsigned(m_bcr0_reg, bcr))
+ return KERN_SUCCESS;
+
+ return KERN_INVALID_ARGUMENT;
+}
+
+#if defined (ENABLE_ARM_SINGLE_STEP)
+
+// return 1 if bit "BIT" is set in "value"
+static inline uint32_t bit(uint32_t value, uint32_t bit)
+{
+ return (value >> bit) & 1u;
+}
+
+// return the bitfield "value[msbit:lsbit]".
+static inline uint32_t bits(uint32_t value, uint32_t msbit, uint32_t lsbit)
+{
+ assert(msbit >= lsbit);
+ uint32_t shift_left = sizeof(value) * 8 - 1 - msbit;
+ value <<= shift_left; // shift anything above the msbit off of the unsigned edge
+ value >>= shift_left + lsbit; // shift it back again down to the lsbit (including undoing any shift from above)
+ return value; // return our result
+}
+
+bool
+MachThreadContext_arm::ConditionPassed(uint8_t condition, uint32_t cpsr)
+{
+ uint32_t cpsr_n = bit(cpsr, 31); // Negative condition code flag
+ uint32_t cpsr_z = bit(cpsr, 30); // Zero condition code flag
+ uint32_t cpsr_c = bit(cpsr, 29); // Carry condition code flag
+ uint32_t cpsr_v = bit(cpsr, 28); // Overflow condition code flag
+
+ switch (condition) {
+ case COND_EQ: // (0x0)
+ if (cpsr_z == 1) return true;
+ break;
+ case COND_NE: // (0x1)
+ if (cpsr_z == 0) return true;
+ break;
+ case COND_CS: // (0x2)
+ if (cpsr_c == 1) return true;
+ break;
+ case COND_CC: // (0x3)
+ if (cpsr_c == 0) return true;
+ break;
+ case COND_MI: // (0x4)
+ if (cpsr_n == 1) return true;
+ break;
+ case COND_PL: // (0x5)
+ if (cpsr_n == 0) return true;
+ break;
+ case COND_VS: // (0x6)
+ if (cpsr_v == 1) return true;
+ break;
+ case COND_VC: // (0x7)
+ if (cpsr_v == 0) return true;
+ break;
+ case COND_HI: // (0x8)
+ if ((cpsr_c == 1) && (cpsr_z == 0)) return true;
+ break;
+ case COND_LS: // (0x9)
+ if ((cpsr_c == 0) || (cpsr_z == 1)) return true;
+ break;
+ case COND_GE: // (0xA)
+ if (cpsr_n == cpsr_v) return true;
+ break;
+ case COND_LT: // (0xB)
+ if (cpsr_n != cpsr_v) return true;
+ break;
+ case COND_GT: // (0xC)
+ if ((cpsr_z == 0) && (cpsr_n == cpsr_v)) return true;
+ break;
+ case COND_LE: // (0xD)
+ if ((cpsr_z == 1) || (cpsr_n != cpsr_v)) return true;
+ break;
+ default:
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+bool
+MachThreadContext_arm::ComputeNextPC(lldb::addr_t currentPC, arm_decoded_instruction_t decodedInstruction, bool currentPCIsThumb, lldb::addr_t *targetPC)
+{
+ lldb::addr_t myTargetPC, addressWherePCLives;
+ lldb::pid_t mypid;
+
+ uint32_t cpsr_c = bit(m_state.gpr.cpsr, 29); // Carry condition code flag
+
+ uint32_t firstOperand=0, secondOperand=0, shiftAmount=0, secondOperandAfterShift=0, immediateValue=0;
+ uint32_t halfwords=0, baseAddress=0, immediateOffset=0, addressOffsetFromRegister=0, addressOffsetFromRegisterAfterShift;
+ uint32_t baseAddressIndex=LLDB_INVALID_INDEX32;
+ uint32_t firstOperandIndex=LLDB_INVALID_INDEX32;
+ uint32_t secondOperandIndex=LLDB_INVALID_INDEX32;
+ uint32_t addressOffsetFromRegisterIndex=LLDB_INVALID_INDEX32;
+ uint32_t shiftRegisterIndex=LLDB_INVALID_INDEX32;
+ uint16_t registerList16, registerList16NoPC;
+ uint8_t registerList8;
+ uint32_t numRegistersToLoad=0;
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: instruction->code=%d", __FUNCTION__, decodedInstruction.instruction->code);
+
+ // Get the following in this switch statement:
+ // - firstOperand, secondOperand, immediateValue, shiftAmount: For arithmetic, logical and move instructions
+ // - baseAddress, immediateOffset, shiftAmount: For LDR
+ // - numRegistersToLoad: For LDM and POP instructions
+ switch (decodedInstruction.instruction->code)
+ {
+ // Arithmetic operations that can change the PC
+ case ARM_INST_ADC:
+ case ARM_INST_ADCS:
+ case ARM_INST_ADD:
+ case ARM_INST_ADDS:
+ case ARM_INST_AND:
+ case ARM_INST_ANDS:
+ case ARM_INST_ASR:
+ case ARM_INST_ASRS:
+ case ARM_INST_BIC:
+ case ARM_INST_BICS:
+ case ARM_INST_EOR:
+ case ARM_INST_EORS:
+ case ARM_INST_ORR:
+ case ARM_INST_ORRS:
+ case ARM_INST_RSB:
+ case ARM_INST_RSBS:
+ case ARM_INST_RSC:
+ case ARM_INST_RSCS:
+ case ARM_INST_SBC:
+ case ARM_INST_SBCS:
+ case ARM_INST_SUB:
+ case ARM_INST_SUBS:
+ switch (decodedInstruction.addressMode)
+ {
+ case ARM_ADDR_DATA_IMM:
+ if (decodedInstruction.numOperands != 3)
+ {
+ LogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=1)
+ firstOperandIndex = decodedInstruction.op[1].value; // first operand register index
+ firstOperand = m_state.gpr.r[firstOperandIndex];
+
+ // Get immediateValue (at index=2)
+ immediateValue = decodedInstruction.op[2].value;
+
+ break;
+
+ case ARM_ADDR_DATA_REG:
+ if (decodedInstruction.numOperands != 3)
+ {
+ LogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=1)
+ firstOperandIndex = decodedInstruction.op[1].value; // first operand register index
+ firstOperand = m_state.gpr.r[firstOperandIndex];
+
+ // Get secondOperand register value (at index=2)
+ secondOperandIndex = decodedInstruction.op[2].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ break;
+
+ case ARM_ADDR_DATA_SCALED_IMM:
+ if (decodedInstruction.numOperands != 4)
+ {
+ LogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=1)
+ firstOperandIndex = decodedInstruction.op[1].value; // first operand register index
+ firstOperand = m_state.gpr.r[firstOperandIndex];
+
+ // Get secondOperand register value (at index=2)
+ secondOperandIndex = decodedInstruction.op[2].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ // Get shiftAmount as immediate value (at index=3)
+ shiftAmount = decodedInstruction.op[3].value;
+
+ break;
+
+
+ case ARM_ADDR_DATA_SCALED_REG:
+ if (decodedInstruction.numOperands != 4)
+ {
+ LogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=1)
+ firstOperandIndex = decodedInstruction.op[1].value; // first operand register index
+ firstOperand = m_state.gpr.r[firstOperandIndex];
+
+ // Get secondOperand register value (at index=2)
+ secondOperandIndex = decodedInstruction.op[2].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ // Get shiftAmount from register (at index=3)
+ shiftRegisterIndex = decodedInstruction.op[3].value; // second operand register index
+ shiftAmount = m_state.gpr.r[shiftRegisterIndex];
+
+ break;
+
+ case THUMB_ADDR_HR_HR:
+ if (decodedInstruction.numOperands != 2)
+ {
+ LogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=0)
+ firstOperandIndex = decodedInstruction.op[0].value; // first operand register index
+ firstOperand = m_state.gpr.r[firstOperandIndex];
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[1].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ // Logical shifts and move operations that can change the PC
+ case ARM_INST_LSL:
+ case ARM_INST_LSLS:
+ case ARM_INST_LSR:
+ case ARM_INST_LSRS:
+ case ARM_INST_MOV:
+ case ARM_INST_MOVS:
+ case ARM_INST_MVN:
+ case ARM_INST_MVNS:
+ case ARM_INST_ROR:
+ case ARM_INST_RORS:
+ case ARM_INST_RRX:
+ case ARM_INST_RRXS:
+ // In these cases, the firstOperand is always 0, as if it does not exist
+ switch (decodedInstruction.addressMode)
+ {
+ case ARM_ADDR_DATA_IMM:
+ if (decodedInstruction.numOperands != 2)
+ {
+ LogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get immediateValue (at index=1)
+ immediateValue = decodedInstruction.op[1].value;
+
+ break;
+
+ case ARM_ADDR_DATA_REG:
+ if (decodedInstruction.numOperands != 2)
+ {
+ LogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[1].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ break;
+
+ case ARM_ADDR_DATA_SCALED_IMM:
+ if (decodedInstruction.numOperands != 3)
+ {
+ LogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[2].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ // Get shiftAmount as immediate value (at index=2)
+ shiftAmount = decodedInstruction.op[2].value;
+
+ break;
+
+
+ case ARM_ADDR_DATA_SCALED_REG:
+ if (decodedInstruction.numOperands != 3)
+ {
+ LogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[1].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ // Get shiftAmount from register (at index=2)
+ shiftRegisterIndex = decodedInstruction.op[2].value; // second operand register index
+ shiftAmount = m_state.gpr.r[shiftRegisterIndex];
+
+ break;
+
+ case THUMB_ADDR_HR_HR:
+ if (decodedInstruction.numOperands != 2)
+ {
+ LogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[1].value; // second operand register index
+ secondOperand = m_state.gpr.r[secondOperandIndex];
+
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ // Simple branches, used to hop around within a routine
+ case ARM_INST_B:
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ break;
+
+ // Branch-and-link, used to call ARM subroutines
+ case ARM_INST_BL:
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ break;
+
+ // Branch-and-link with exchange, used to call opposite-mode subroutines
+ case ARM_INST_BLX:
+ if ((decodedInstruction.addressMode == ARM_ADDR_BRANCH_IMM) ||
+ (decodedInstruction.addressMode == THUMB_ADDR_UNCOND))
+ {
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ }
+ else // addressMode == ARM_ADDR_BRANCH_REG
+ {
+ // Unknown target unless we're branching to the PC itself,
+ // although this may not work properly with BLX
+ if (decodedInstruction.op[REG_RD].value == PC_REG)
+ {
+ // this should (almost) never happen
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ }
+
+ // Get the branch address and return
+ if (decodedInstruction.numOperands != 1)
+ {
+ LogError("Expected 1 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get branch address in register (at index=0)
+ *targetPC = m_state.gpr.r[decodedInstruction.op[0].value];
+ return true;
+ }
+ break;
+
+ // Branch with exchange, used to hop to opposite-mode code
+ // Branch to Jazelle code, used to execute Java; included here since it
+ // acts just like BX unless the Jazelle unit is active and JPC is
+ // already loaded into it.
+ case ARM_INST_BX:
+ case ARM_INST_BXJ:
+ // Unknown target unless we're branching to the PC itself,
+ // although this can never switch to Thumb mode and is
+ // therefore pretty much useless
+ if (decodedInstruction.op[REG_RD].value == PC_REG)
+ {
+ // this should (almost) never happen
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ }
+
+ // Get the branch address and return
+ if (decodedInstruction.numOperands != 1)
+ {
+ LogError("Expected 1 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get branch address in register (at index=0)
+ *targetPC = m_state.gpr.r[decodedInstruction.op[0].value];
+ return true;
+ break;
+
+ // Compare and branch on zero/non-zero (Thumb-16 only)
+ // Unusual condition check built into the instruction
+ case ARM_INST_CBZ:
+ case ARM_INST_CBNZ:
+ // Branch address is known at compile time
+ // Get the branch address and return
+ if (decodedInstruction.numOperands != 2)
+ {
+ LogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get branch address as an immediate value (at index=1)
+ *targetPC = decodedInstruction.op[1].value;
+ return true;
+ break;
+
+ // Load register can be used to load PC, usually with a function pointer
+ case ARM_INST_LDR:
+ if (decodedInstruction.op[REG_RD].value != PC_REG)
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+ switch (decodedInstruction.addressMode)
+ {
+ case ARM_ADDR_LSWUB_IMM:
+ case ARM_ADDR_LSWUB_IMM_PRE:
+ case ARM_ADDR_LSWUB_IMM_POST:
+ if (decodedInstruction.numOperands != 3)
+ {
+ LogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get baseAddress from register (at index=1)
+ baseAddressIndex = decodedInstruction.op[1].value;
+ baseAddress = m_state.gpr.r[baseAddressIndex];
+
+ // Get immediateOffset (at index=2)
+ immediateOffset = decodedInstruction.op[2].value;
+ break;
+
+ case ARM_ADDR_LSWUB_REG:
+ case ARM_ADDR_LSWUB_REG_PRE:
+ case ARM_ADDR_LSWUB_REG_POST:
+ if (decodedInstruction.numOperands != 3)
+ {
+ LogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get baseAddress from register (at index=1)
+ baseAddressIndex = decodedInstruction.op[1].value;
+ baseAddress = m_state.gpr.r[baseAddressIndex];
+
+ // Get immediateOffset from register (at index=2)
+ addressOffsetFromRegisterIndex = decodedInstruction.op[2].value;
+ addressOffsetFromRegister = m_state.gpr.r[addressOffsetFromRegisterIndex];
+
+ break;
+
+ case ARM_ADDR_LSWUB_SCALED:
+ case ARM_ADDR_LSWUB_SCALED_PRE:
+ case ARM_ADDR_LSWUB_SCALED_POST:
+ if (decodedInstruction.numOperands != 4)
+ {
+ LogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get baseAddress from register (at index=1)
+ baseAddressIndex = decodedInstruction.op[1].value;
+ baseAddress = m_state.gpr.r[baseAddressIndex];
+
+ // Get immediateOffset from register (at index=2)
+ addressOffsetFromRegisterIndex = decodedInstruction.op[2].value;
+ addressOffsetFromRegister = m_state.gpr.r[addressOffsetFromRegisterIndex];
+
+ // Get shiftAmount (at index=3)
+ shiftAmount = decodedInstruction.op[3].value;
+
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ // 32b load multiple operations can load the PC along with everything else,
+ // usually to return from a function call
+ case ARM_INST_LDMDA:
+ case ARM_INST_LDMDB:
+ case ARM_INST_LDMIA:
+ case ARM_INST_LDMIB:
+ if (decodedInstruction.op[LDM_REGLIST].value & PC_REGLIST_BIT)
+ {
+ if (decodedInstruction.numOperands != 2)
+ {
+ LogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get baseAddress from register (at index=0)
+ baseAddressIndex = decodedInstruction.op[0].value;
+ baseAddress = m_state.gpr.r[baseAddressIndex];
+
+ // Get registerList from register (at index=1)
+ registerList16 = (uint16_t)decodedInstruction.op[1].value;
+
+ // Count number of registers to load in the multiple register list excluding the PC
+ registerList16NoPC = registerList16&0x3FFF; // exclude the PC
+ numRegistersToLoad=0;
+ for (int i = 0; i < 16; i++)
+ {
+ if (registerList16NoPC & 0x1) numRegistersToLoad++;
+ registerList16NoPC = registerList16NoPC >> 1;
+ }
+ }
+ else
+ {
+ LogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+ break;
+
+ // Normal 16-bit LD multiple can't touch R15, but POP can
+ case ARM_INST_POP: // Can also get the PC & updates SP
+ // Get baseAddress from SP (at index=0)
+ baseAddress = m_state.gpr.__sp;
+
+ if (decodedInstruction.thumb16b)
+ {
+ // Get registerList from register (at index=0)
+ registerList8 = (uint8_t)decodedInstruction.op[0].value;
+
+ // Count number of registers to load in the multiple register list
+ numRegistersToLoad=0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (registerList8 & 0x1) numRegistersToLoad++;
+ registerList8 = registerList8 >> 1;
+ }
+ }
+ else
+ {
+ // Get registerList from register (at index=0)
+ registerList16 = (uint16_t)decodedInstruction.op[0].value;
+
+ // Count number of registers to load in the multiple register list excluding the PC
+ registerList16NoPC = registerList16&0x3FFF; // exclude the PC
+ numRegistersToLoad=0;
+ for (int i = 0; i < 16; i++)
+ {
+ if (registerList16NoPC & 0x1) numRegistersToLoad++;
+ registerList16NoPC = registerList16NoPC >> 1;
+ }
+ }
+ break;
+
+ // 16b TBB and TBH instructions load a jump address from a table
+ case ARM_INST_TBB:
+ case ARM_INST_TBH:
+ // Get baseAddress from register (at index=0)
+ baseAddressIndex = decodedInstruction.op[0].value;
+ baseAddress = m_state.gpr.r[baseAddressIndex];
+
+ // Get immediateOffset from register (at index=1)
+ addressOffsetFromRegisterIndex = decodedInstruction.op[1].value;
+ addressOffsetFromRegister = m_state.gpr.r[addressOffsetFromRegisterIndex];
+ break;
+
+ // ThumbEE branch-to-handler instructions: Jump to handlers at some offset
+ // from a special base pointer register (which is unknown at disassembly time)
+ case ARM_INST_HB:
+ case ARM_INST_HBP:
+// TODO: ARM_INST_HB, ARM_INST_HBP
+ break;
+
+ case ARM_INST_HBL:
+ case ARM_INST_HBLP:
+// TODO: ARM_INST_HBL, ARM_INST_HBLP
+ break;
+
+ // Breakpoint and software interrupt jump to interrupt handler (always ARM)
+ case ARM_INST_BKPT:
+ case ARM_INST_SMC:
+ case ARM_INST_SVC:
+
+ // Return from exception, obviously modifies PC [interrupt only!]
+ case ARM_INST_RFEDA:
+ case ARM_INST_RFEDB:
+ case ARM_INST_RFEIA:
+ case ARM_INST_RFEIB:
+
+ // Other instructions either can't change R15 or are "undefined" if you do,
+ // so no sane compiler should ever generate them & we don't care here.
+ // Also, R15 can only legally be used in a read-only manner for the
+ // various ARM addressing mode (to get PC-relative addressing of constants),
+ // but can NOT be used with any of the update modes.
+ default:
+ LogError("%s should not be called for instruction code %d!", __FUNCTION__, decodedInstruction.instruction->code);
+ return false;
+ break;
+ }
+
+ // Adjust PC if PC is one of the input operands
+ if (baseAddressIndex == PC_REG)
+ {
+ if (currentPCIsThumb)
+ baseAddress += 4;
+ else
+ baseAddress += 8;
+ }
+
+ if (firstOperandIndex == PC_REG)
+ {
+ if (currentPCIsThumb)
+ firstOperand += 4;
+ else
+ firstOperand += 8;
+ }
+
+ if (secondOperandIndex == PC_REG)
+ {
+ if (currentPCIsThumb)
+ secondOperand += 4;
+ else
+ secondOperand += 8;
+ }
+
+ if (addressOffsetFromRegisterIndex == PC_REG)
+ {
+ if (currentPCIsThumb)
+ addressOffsetFromRegister += 4;
+ else
+ addressOffsetFromRegister += 8;
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE,
+ "%s: firstOperand=%8.8x, secondOperand=%8.8x, immediateValue = %d, shiftAmount = %d, baseAddress = %8.8x, addressOffsetFromRegister = %8.8x, immediateOffset = %d, numRegistersToLoad = %d",
+ __FUNCTION__,
+ firstOperand,
+ secondOperand,
+ immediateValue,
+ shiftAmount,
+ baseAddress,
+ addressOffsetFromRegister,
+ immediateOffset,
+ numRegistersToLoad);
+
+
+ // Calculate following values after applying shiftAmount:
+ // - immediateOffsetAfterShift, secondOperandAfterShift
+
+ switch (decodedInstruction.scaleMode)
+ {
+ case ARM_SCALE_NONE:
+ addressOffsetFromRegisterAfterShift = addressOffsetFromRegister;
+ secondOperandAfterShift = secondOperand;
+ break;
+
+ case ARM_SCALE_LSL: // Logical shift left
+ addressOffsetFromRegisterAfterShift = addressOffsetFromRegister << shiftAmount;
+ secondOperandAfterShift = secondOperand << shiftAmount;
+ break;
+
+ case ARM_SCALE_LSR: // Logical shift right
+ addressOffsetFromRegisterAfterShift = addressOffsetFromRegister >> shiftAmount;
+ secondOperandAfterShift = secondOperand >> shiftAmount;
+ break;
+
+ case ARM_SCALE_ASR: // Arithmetic shift right
+ asm("mov %0, %1, asr %2" : "=r" (addressOffsetFromRegisterAfterShift) : "r" (addressOffsetFromRegister), "r" (shiftAmount));
+ asm("mov %0, %1, asr %2" : "=r" (secondOperandAfterShift) : "r" (secondOperand), "r" (shiftAmount));
+ break;
+
+ case ARM_SCALE_ROR: // Rotate right
+ asm("mov %0, %1, ror %2" : "=r" (addressOffsetFromRegisterAfterShift) : "r" (addressOffsetFromRegister), "r" (shiftAmount));
+ asm("mov %0, %1, ror %2" : "=r" (secondOperandAfterShift) : "r" (secondOperand), "r" (shiftAmount));
+ break;
+
+ case ARM_SCALE_RRX: // Rotate right, pulling in carry (1-bit shift only)
+ asm("mov %0, %1, rrx" : "=r" (addressOffsetFromRegisterAfterShift) : "r" (addressOffsetFromRegister));
+ asm("mov %0, %1, rrx" : "=r" (secondOperandAfterShift) : "r" (secondOperand));
+ break;
+ }
+
+ // Emulate instruction to calculate targetPC
+ // All branches are already handled in the first switch statement. A branch should not reach this switch
+ switch (decodedInstruction.instruction->code)
+ {
+ // Arithmetic operations that can change the PC
+ case ARM_INST_ADC:
+ case ARM_INST_ADCS:
+ // Add with Carry
+ *targetPC = firstOperand + (secondOperandAfterShift + immediateValue) + cpsr_c;
+ break;
+
+ case ARM_INST_ADD:
+ case ARM_INST_ADDS:
+ *targetPC = firstOperand + (secondOperandAfterShift + immediateValue);
+ break;
+
+ case ARM_INST_AND:
+ case ARM_INST_ANDS:
+ *targetPC = firstOperand & (secondOperandAfterShift + immediateValue);
+ break;
+
+ case ARM_INST_ASR:
+ case ARM_INST_ASRS:
+ asm("mov %0, %1, asr %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_BIC:
+ case ARM_INST_BICS:
+ asm("bic %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_EOR:
+ case ARM_INST_EORS:
+ asm("eor %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_ORR:
+ case ARM_INST_ORRS:
+ asm("orr %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_RSB:
+ case ARM_INST_RSBS:
+ asm("rsb %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_RSC:
+ case ARM_INST_RSCS:
+ myTargetPC = secondOperandAfterShift - (firstOperand + !cpsr_c);
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_SBC:
+ case ARM_INST_SBCS:
+ asm("sbc %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue + !cpsr_c));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_SUB:
+ case ARM_INST_SUBS:
+ asm("sub %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ // Logical shifts and move operations that can change the PC
+ case ARM_INST_LSL:
+ case ARM_INST_LSLS:
+ case ARM_INST_LSR:
+ case ARM_INST_LSRS:
+ case ARM_INST_MOV:
+ case ARM_INST_MOVS:
+ case ARM_INST_ROR:
+ case ARM_INST_RORS:
+ case ARM_INST_RRX:
+ case ARM_INST_RRXS:
+ myTargetPC = secondOperandAfterShift + immediateValue;
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_MVN:
+ case ARM_INST_MVNS:
+ myTargetPC = !(secondOperandAfterShift + immediateValue);
+ *targetPC = myTargetPC;
+ break;
+
+ // Load register can be used to load PC, usually with a function pointer
+ case ARM_INST_LDR:
+ switch (decodedInstruction.addressMode) {
+ case ARM_ADDR_LSWUB_IMM_POST:
+ case ARM_ADDR_LSWUB_REG_POST:
+ case ARM_ADDR_LSWUB_SCALED_POST:
+ addressWherePCLives = baseAddress;
+ break;
+
+ case ARM_ADDR_LSWUB_IMM:
+ case ARM_ADDR_LSWUB_REG:
+ case ARM_ADDR_LSWUB_SCALED:
+ case ARM_ADDR_LSWUB_IMM_PRE:
+ case ARM_ADDR_LSWUB_REG_PRE:
+ case ARM_ADDR_LSWUB_SCALED_PRE:
+ addressWherePCLives = baseAddress + (addressOffsetFromRegisterAfterShift + immediateOffset);
+ break;
+
+ default:
+ break;
+ }
+
+ mypid = m_thread.ProcessID();
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, sizeof(lldb::addr_t), &myTargetPC) != sizeof(lldb::addr_t))
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ // 32b load multiple operations can load the PC along with everything else,
+ // usually to return from a function call
+ case ARM_INST_LDMDA:
+ mypid = m_thread.ProcessID();
+ addressWherePCLives = baseAddress;
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, sizeof(lldb::addr_t), &myTargetPC) != sizeof(lldb::addr_t))
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_LDMDB:
+ mypid = m_thread.ProcessID();
+ addressWherePCLives = baseAddress - 4;
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, sizeof(lldb::addr_t), &myTargetPC) != sizeof(lldb::addr_t))
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_LDMIB:
+ mypid = m_thread.ProcessID();
+ addressWherePCLives = baseAddress + numRegistersToLoad*4 + 4;
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, sizeof(lldb::addr_t), &myTargetPC) != sizeof(lldb::addr_t))
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_LDMIA: // same as pop
+ // Normal 16-bit LD multiple can't touch R15, but POP can
+ case ARM_INST_POP: // Can also get the PC & updates SP
+ mypid = m_thread.ProcessID();
+ addressWherePCLives = baseAddress + numRegistersToLoad*4;
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, sizeof(lldb::addr_t), &myTargetPC) != sizeof(lldb::addr_t))
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ // 16b TBB and TBH instructions load a jump address from a table
+ case ARM_INST_TBB:
+ mypid = m_thread.ProcessID();
+ addressWherePCLives = baseAddress + addressOffsetFromRegisterAfterShift;
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, 1, &halfwords) != 1)
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the TBB instruction!", addressWherePCLives);
+ return false;
+ }
+ // add 4 to currentPC since we are in Thumb mode and then add 2*halfwords
+ *targetPC = (currentPC + 4) + 2*halfwords;
+ break;
+
+ case ARM_INST_TBH:
+ mypid = m_thread.ProcessID();
+ addressWherePCLives = ((baseAddress + (addressOffsetFromRegisterAfterShift << 1)) & ~0x1);
+ if (PDProcessMemoryRead(mypid, addressWherePCLives, 2, &halfwords) != 2)
+ {
+ LogError("Could not read memory at %8.8x to get targetPC when processing the TBH instruction!", addressWherePCLives);
+ return false;
+ }
+ // add 4 to currentPC since we are in Thumb mode and then add 2*halfwords
+ *targetPC = (currentPC + 4) + 2*halfwords;
+ break;
+
+ // ThumbEE branch-to-handler instructions: Jump to handlers at some offset
+ // from a special base pointer register (which is unknown at disassembly time)
+ case ARM_INST_HB:
+ case ARM_INST_HBP:
+ // TODO: ARM_INST_HB, ARM_INST_HBP
+ break;
+
+ case ARM_INST_HBL:
+ case ARM_INST_HBLP:
+ // TODO: ARM_INST_HBL, ARM_INST_HBLP
+ break;
+
+ // Breakpoint and software interrupt jump to interrupt handler (always ARM)
+ case ARM_INST_BKPT:
+ case ARM_INST_SMC:
+ case ARM_INST_SVC:
+ // TODO: ARM_INST_BKPT, ARM_INST_SMC, ARM_INST_SVC
+ break;
+
+ // Return from exception, obviously modifies PC [interrupt only!]
+ case ARM_INST_RFEDA:
+ case ARM_INST_RFEDB:
+ case ARM_INST_RFEIA:
+ case ARM_INST_RFEIB:
+ // TODO: ARM_INST_RFEDA, ARM_INST_RFEDB, ARM_INST_RFEIA, ARM_INST_RFEIB
+ break;
+
+ // Other instructions either can't change R15 or are "undefined" if you do,
+ // so no sane compiler should ever generate them & we don't care here.
+ // Also, R15 can only legally be used in a read-only manner for the
+ // various ARM addressing mode (to get PC-relative addressing of constants),
+ // but can NOT be used with any of the update modes.
+ default:
+ LogError("%s should not be called for instruction code %d!", __FUNCTION__, decodedInstruction.instruction->code);
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+void
+MachThreadContext_arm::EvaluateNextInstructionForSoftwareBreakpointSetup(lldb::addr_t currentPC, uint32_t cpsr, bool currentPCIsThumb, lldb::addr_t *nextPC, bool *nextPCIsThumb)
+{
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "MachThreadContext_arm::EvaluateNextInstructionForSoftwareBreakpointSetup() called");
+
+ lldb::addr_t targetPC = LLDB_INVALID_ADDRESS;
+ uint32_t registerValue;
+ arm_error_t decodeError;
+ lldb::addr_t currentPCInITBlock, nextPCInITBlock;
+ int i;
+ bool last_decoded_instruction_executes = true;
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: default nextPC=0x%8.8x (%s)", __FUNCTION__, *nextPC, *nextPCIsThumb ? "Thumb" : "ARM");
+
+ // Update *nextPC and *nextPCIsThumb for special cases
+ if (m_last_decode_thumb.itBlockRemaining) // we are in an IT block
+ {
+ // Set the nextPC to the PC of the instruction which will execute in the IT block
+ // If none of the instruction execute in the IT block based on the condition flags,
+ // then point to the instruction immediately following the IT block
+ const int itBlockRemaining = m_last_decode_thumb.itBlockRemaining;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: itBlockRemaining=%8.8x", __FUNCTION__, itBlockRemaining);
+
+ // Determine the PC at which the next instruction resides
+ if (m_last_decode_arm.thumb16b)
+ currentPCInITBlock = currentPC + 2;
+ else
+ currentPCInITBlock = currentPC + 4;
+
+ for (i = 0; i < itBlockRemaining; i++)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: currentPCInITBlock=%8.8x", __FUNCTION__, currentPCInITBlock);
+ decodeError = DecodeInstructionUsingDisassembler(currentPCInITBlock, cpsr, &m_last_decode_arm, &m_last_decode_thumb, &nextPCInITBlock);
+
+ if (decodeError != ARM_SUCCESS)
+ LogError("unable to disassemble instruction at 0x%8.8lx", currentPCInITBlock);
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: condition=%d", __FUNCTION__, m_last_decode_arm.condition);
+ if (ConditionPassed(m_last_decode_arm.condition, cpsr))
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Condition codes matched for instruction %d", __FUNCTION__, i);
+ break; // break from the for loop
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Condition codes DID NOT matched for instruction %d", __FUNCTION__, i);
+ }
+
+ // update currentPC and nextPCInITBlock
+ currentPCInITBlock = nextPCInITBlock;
+ }
+
+ if (i == itBlockRemaining) // We came out of the IT block without executing any instructions
+ last_decoded_instruction_executes = false;
+
+ *nextPC = currentPCInITBlock;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: After IT block step-through: *nextPC=%8.8x", __FUNCTION__, *nextPC);
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE,
+ "%s: cpsr = %8.8x, thumb16b = %d, thumb = %d, branch = %d, conditional = %d, knownTarget = %d, links = %d, canSwitchMode = %d, doesSwitchMode = %d",
+ __FUNCTION__,
+ cpsr,
+ m_last_decode_arm.thumb16b,
+ m_last_decode_arm.thumb,
+ m_last_decode_arm.branch,
+ m_last_decode_arm.conditional,
+ m_last_decode_arm.knownTarget,
+ m_last_decode_arm.links,
+ m_last_decode_arm.canSwitchMode,
+ m_last_decode_arm.doesSwitchMode);
+
+
+ if (last_decoded_instruction_executes && // Was this a conditional instruction that did execute?
+ m_last_decode_arm.branch && // Can this instruction change the PC?
+ (m_last_decode_arm.instruction->code != ARM_INST_SVC)) // If this instruction is not an SVC instruction
+ {
+ // Set targetPC. Compute if needed.
+ if (m_last_decode_arm.knownTarget)
+ {
+ // Fixed, known PC-relative
+ targetPC = m_last_decode_arm.targetPC;
+ }
+ else
+ {
+ // if targetPC is not known at compile time (PC-relative target), compute targetPC
+ if (!ComputeNextPC(currentPC, m_last_decode_arm, currentPCIsThumb, &targetPC))
+ {
+ LogError("%s: Unable to compute targetPC for instruction at 0x%8.8lx", __FUNCTION__, currentPC);
+ targetPC = LLDB_INVALID_ADDRESS;
+ }
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: targetPC=0x%8.8x, cpsr=0x%8.8x, condition=0x%hhx", __FUNCTION__, targetPC, cpsr, m_last_decode_arm.condition);
+
+ // Refine nextPC computation
+ if ((m_last_decode_arm.instruction->code == ARM_INST_CBZ) ||
+ (m_last_decode_arm.instruction->code == ARM_INST_CBNZ))
+ {
+ // Compare and branch on zero/non-zero (Thumb-16 only)
+ // Unusual condition check built into the instruction
+ registerValue = m_state.gpr.r[m_last_decode_arm.op[REG_RD].value];
+
+ if (m_last_decode_arm.instruction->code == ARM_INST_CBZ)
+ {
+ if (registerValue == 0)
+ *nextPC = targetPC;
+ }
+ else
+ {
+ if (registerValue != 0)
+ *nextPC = targetPC;
+ }
+ }
+ else if (m_last_decode_arm.conditional) // Is the change conditional on flag results?
+ {
+ if (ConditionPassed(m_last_decode_arm.condition, cpsr)) // conditions match
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Condition matched!", __FUNCTION__);
+ *nextPC = targetPC;
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Condition did not match!", __FUNCTION__);
+ }
+ }
+ else
+ {
+ *nextPC = targetPC;
+ }
+
+ // Refine nextPCIsThumb computation
+ if (m_last_decode_arm.doesSwitchMode)
+ {
+ *nextPCIsThumb = !currentPCIsThumb;
+ }
+ else if (m_last_decode_arm.canSwitchMode)
+ {
+ // Legal to switch ARM <--> Thumb mode with this branch
+ // dependent on bit[0] of targetPC
+ *nextPCIsThumb = (*nextPC & 1u) != 0;
+ }
+ else
+ {
+ *nextPCIsThumb = currentPCIsThumb;
+ }
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: calculated nextPC=0x%8.8x (%s)", __FUNCTION__, *nextPC, *nextPCIsThumb ? "Thumb" : "ARM");
+}
+
+
+arm_error_t
+MachThreadContext_arm::DecodeInstructionUsingDisassembler(lldb::addr_t curr_pc, uint32_t curr_cpsr, arm_decoded_instruction_t *decodedInstruction, thumb_static_data_t *thumbStaticData, lldb::addr_t *next_pc)
+{
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: pc=0x%8.8x, cpsr=0x%8.8x", __FUNCTION__, curr_pc, curr_cpsr);
+
+ const uint32_t isetstate_mask = MASK_CPSR_T | MASK_CPSR_J;
+ const uint32_t curr_isetstate = curr_cpsr & isetstate_mask;
+ uint32_t opcode32;
+ lldb::addr_t nextPC = curr_pc;
+ arm_error_t decodeReturnCode = ARM_SUCCESS;
+
+ m_last_decode_pc = curr_pc;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: last_decode_pc=0x%8.8x", __FUNCTION__, m_last_decode_pc);
+
+ switch (curr_isetstate) {
+ case 0x0: // ARM Instruction
+ // Read the ARM opcode
+ if (m_thread.Process()->Task().ReadMemory(curr_pc, 4, &opcode32) != 4)
+ {
+ LogError("unable to read opcode bits 31:0 for an ARM opcode at 0x%8.8lx", curr_pc);
+ decodeReturnCode = ARM_ERROR;
+ }
+ else
+ {
+ nextPC += 4;
+ decodeReturnCode = ArmDisassembler((uint64_t)curr_pc, opcode32, false, decodedInstruction, NULL, 0, NULL, 0);
+
+ if (decodeReturnCode != ARM_SUCCESS)
+ LogError("Unable to decode ARM instruction 0x%8.8x at 0x%8.8lx", opcode32, curr_pc);
+ }
+ break;
+
+ case 0x20: // Thumb Instruction
+ uint16_t opcode16;
+ // Read the a 16 bit Thumb opcode
+ if (m_thread.Process()->Task().ReadMemory(curr_pc, 2, &opcode16) != 2)
+ {
+ LogError("unable to read opcode bits 15:0 for a thumb opcode at 0x%8.8lx", curr_pc);
+ decodeReturnCode = ARM_ERROR;
+ }
+ else
+ {
+ nextPC += 2;
+ opcode32 = opcode16;
+
+ decodeReturnCode = ThumbDisassembler((uint64_t)curr_pc, opcode16, false, false, thumbStaticData, decodedInstruction, NULL, 0, NULL, 0);
+
+ switch (decodeReturnCode) {
+ case ARM_SKIP:
+ // 32 bit thumb opcode
+ nextPC += 2;
+ if (m_thread.Process()->Task().ReadMemory(curr_pc+2, 2, &opcode16) != 2)
+ {
+ LogError("unable to read opcode bits 15:0 for a thumb opcode at 0x%8.8lx", curr_pc+2);
+ }
+ else
+ {
+ opcode32 = (opcode32 << 16) | opcode16;
+
+ decodeReturnCode = ThumbDisassembler((uint64_t)(curr_pc+2), opcode16, false, false, thumbStaticData, decodedInstruction, NULL, 0, NULL, 0);
+
+ if (decodeReturnCode != ARM_SUCCESS)
+ LogError("Unable to decode 2nd half of Thumb instruction 0x%8.4hx at 0x%8.8lx", opcode16, curr_pc+2);
+ break;
+ }
+ break;
+
+ case ARM_SUCCESS:
+ // 16 bit thumb opcode; at this point we are done decoding the opcode
+ break;
+
+ default:
+ LogError("Unable to decode Thumb instruction 0x%8.4hx at 0x%8.8lx", opcode16, curr_pc);
+ decodeReturnCode = ARM_ERROR;
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (next_pc)
+ *next_pc = nextPC;
+
+ return decodeReturnCode;
+}
+
+bool
+MachThreadContext_arm::BreakpointHit(lldb::pid_t pid, lldb::tid_t tid, lldb::user_id_t breakID, void *baton)
+{
+ lldb::addr_t bkpt_pc = (lldb::addr_t)baton;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s(pid = %i, tid = %4.4x, breakID = %u, baton = %p): Setting PC to 0x%8.8x", __FUNCTION__, pid, tid, breakID, baton, bkpt_pc);
+ return PDThreadSetRegisterValueByID(pid, tid, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, bkpt_pc);
+}
+
+// Set the single step bit in the processor status register.
+kern_return_t
+MachThreadContext_arm::SetSingleStepSoftwareBreakpoints()
+{
+ Error err;
+ err = ReadGPRRegisters(false);
+
+ if (err.Fail())
+ {
+ err.Log("%s: failed to read the GPR registers", __FUNCTION__);
+ return err.GetError();
+ }
+
+ lldb::addr_t curr_pc = m_state.gpr.r[15];
+ uint32_t curr_cpsr = m_state.gpr.__cpsr;
+ lldb::addr_t next_pc = curr_pc;
+
+ bool curr_pc_is_thumb = (m_state.gpr.__cpsr & 0x20) != 0;
+ bool next_pc_is_thumb = curr_pc_is_thumb;
+
+ uint32_t curr_itstate = ((curr_cpsr & 0x6000000) >> 25) | ((curr_cpsr & 0xFC00) >> 8);
+ bool inITBlock = (curr_itstate & 0xF) ? 1 : 0;
+ bool lastInITBlock = ((curr_itstate & 0xF) == 0x8) ? 1 : 0;
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: curr_pc=0x%8.8x (%s), curr_itstate=0x%x, inITBlock=%d, lastInITBlock=%d", __FUNCTION__, curr_pc, curr_pc_is_thumb ? "Thumb" : "ARM", curr_itstate, inITBlock, lastInITBlock);
+
+ // If the instruction is not in the IT block, then decode using the Disassembler and compute next_pc
+ if (!inITBlock)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Decoding an instruction NOT in the IT block", __FUNCTION__);
+
+ arm_error_t decodeReturnCode = DecodeInstructionUsingDisassembler(curr_pc, curr_cpsr, &m_last_decode_arm, &m_last_decode_thumb, &next_pc);
+
+ if (decodeReturnCode != ARM_SUCCESS)
+ {
+ err = KERN_INVALID_ARGUMENT;
+ LogError("MachThreadContext_arm::SetSingleStepSoftwareBreakpoints: Unable to disassemble instruction at 0x%8.8lx", curr_pc);
+ }
+ }
+ else
+ {
+ next_pc = curr_pc + ((m_last_decode_arm.thumb16b) ? 2 : 4);
+ }
+
+ // Instruction is NOT in the IT block OR
+ if (!inITBlock)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: normal instruction", __FUNCTION__);
+ EvaluateNextInstructionForSoftwareBreakpointSetup(curr_pc, m_state.gpr.__cpsr, curr_pc_is_thumb, &next_pc, &next_pc_is_thumb);
+ }
+ else if (inITBlock && !m_last_decode_arm.setsFlags)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: IT instruction that doesn't set flags", __FUNCTION__);
+ EvaluateNextInstructionForSoftwareBreakpointSetup(curr_pc, m_state.gpr.__cpsr, curr_pc_is_thumb, &next_pc, &next_pc_is_thumb);
+ }
+ else if (lastInITBlock && m_last_decode_arm.branch)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: IT instruction which last in the IT block and is a branch", __FUNCTION__);
+ EvaluateNextInstructionForSoftwareBreakpointSetup(curr_pc, m_state.gpr.__cpsr, curr_pc_is_thumb, &next_pc, &next_pc_is_thumb);
+ }
+ else
+ {
+ // Instruction is in IT block and can modify the CPSR flags
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: IT instruction that sets flags", __FUNCTION__);
+
+ // NOTE: When this point of code is reached, the instruction at curr_pc has already been decoded
+ // inside the function ShouldStop (). Therefore m_last_decode_arm, m_last_decode_thumb
+ // reflect the decoded instruction at curr_pc
+
+ // If we find an instruction inside the IT block which will set/modify the condition flags (NZCV bits in CPSR),
+ // we set breakpoints at all remaining instructions inside the IT block starting from the instruction immediately
+ // following this one AND a breakpoint at the instruction immediately following the IT block. We do this because
+ // we cannot determine the next_pc until the instruction at which we are currently stopped executes. Hence we
+ // insert (m_last_decode_thumb.itBlockRemaining+1) 16-bit Thumb breakpoints at consecutive memory locations
+ // starting at addrOfNextInstructionInITBlock. We record these breakpoints in class variable m_sw_single_step_itblock_break_id[],
+ // and also record the total number of IT breakpoints set in the variable 'm_sw_single_step_itblock_break_count'.
+
+ // The instructions inside the IT block, which are replaced by the 16-bit Thumb breakpoints (opcode=0xDEFE)
+ // instructions, can be either Thumb-16 or Thumb-32. When a Thumb-32 instruction (say, inst#1) is replaced Thumb
+ // by a 16-bit breakpoint (OS only supports 16-bit breakpoints in Thumb mode and 32-bit breakpoints in ARM mode), the
+ // breakpoint for the next instruction (say instr#2) is saved in the upper half of this Thumb-32 (instr#1)
+ // instruction. Hence if the execution stops at Breakpoint2 corresponding to instr#2, the PC is offset by 16-bits.
+ // We therefore have to keep track of PC of each instruction in the IT block that is being replaced with the 16-bit
+ // Thumb breakpoint, to ensure that when the breakpoint is hit, the PC is adjusted to the correct value. We save
+ // the actual PC corresponding to each instruction in the IT block by associating a call back with each breakpoint
+ // we set and passing it as a baton. When the breakpoint hits and the callback routine is called, the routine
+ // adjusts the PC based on the baton that is passed to it.
+
+ lldb::addr_t addrOfNextInstructionInITBlock, pcInITBlock, nextPCInITBlock, bpAddressInITBlock;
+ uint16_t opcode16;
+ uint32_t opcode32;
+
+ addrOfNextInstructionInITBlock = (m_last_decode_arm.thumb16b) ? curr_pc + 2 : curr_pc + 4;
+
+ pcInITBlock = addrOfNextInstructionInITBlock;
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: itBlockRemaining=%d", __FUNCTION__, m_last_decode_thumb.itBlockRemaining);
+
+ m_sw_single_step_itblock_break_count = 0;
+ for (int i = 0; i <= m_last_decode_thumb.itBlockRemaining; i++)
+ {
+ if (LLDB_BREAK_ID_IS_VALID(m_sw_single_step_itblock_break_id[i]))
+ {
+ LogError("FunctionProfiler::SetSingleStepSoftwareBreakpoints(): Array m_sw_single_step_itblock_break_id should not contain any valid breakpoint IDs at this point. But found a valid breakID=%d at index=%d", m_sw_single_step_itblock_break_id[i], i);
+ }
+ else
+ {
+ nextPCInITBlock = pcInITBlock;
+ // Compute nextPCInITBlock based on opcode present at pcInITBlock
+ if (m_thread.Process()->Task().ReadMemory(pcInITBlock, 2, &opcode16) == 2)
+ {
+ opcode32 = opcode16;
+ nextPCInITBlock += 2;
+
+ // Check for 32 bit thumb opcode and read the upper 16 bits if needed
+ if (((opcode32 & 0xE000) == 0xE000) && (opcode32 & 0x1800))
+ {
+ // Adjust 'next_pc_in_itblock' to point to the default next Thumb instruction for
+ // a 32 bit Thumb opcode
+ // Read bits 31:16 of a 32 bit Thumb opcode
+ if (m_thread.Process()->Task().ReadMemory(pcInITBlock+2, 2, &opcode16) == 2)
+ {
+ // 32 bit thumb opcode
+ opcode32 = (opcode32 << 16) | opcode16;
+ nextPCInITBlock += 2;
+ }
+ else
+ {
+ LogError("FunctionProfiler::SetSingleStepSoftwareBreakpoints(): Unable to read opcode bits 31:16 for a 32 bit thumb opcode at pc=0x%8.8lx", nextPCInITBlock);
+ }
+ }
+ }
+ else
+ {
+ LogError("FunctionProfiler::SetSingleStepSoftwareBreakpoints(): Error reading 16-bit Thumb instruction at pc=0x%8.8x", nextPCInITBlock);
+ }
+
+
+ // Set breakpoint and associate a callback function with it
+ bpAddressInITBlock = addrOfNextInstructionInITBlock + 2*i;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Setting IT breakpoint[%d] at address: 0x%8.8x", __FUNCTION__, i, bpAddressInITBlock);
+
+ m_sw_single_step_itblock_break_id[i] = m_thread.Process()->CreateBreakpoint(bpAddressInITBlock, 2, false, m_thread.GetID());
+ if (!LLDB_BREAK_ID_IS_VALID(m_sw_single_step_itblock_break_id[i]))
+ err = KERN_INVALID_ARGUMENT;
+ else
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: Set IT breakpoint[%i]=%d set at 0x%8.8x for instruction at 0x%8.8x", __FUNCTION__, i, m_sw_single_step_itblock_break_id[i], bpAddressInITBlock, pcInITBlock);
+
+ // Set the breakpoint callback for these special IT breakpoints
+ // so that if one of these breakpoints gets hit, it knows to
+ // update the PC to the original address of the conditional
+ // IT instruction.
+ PDBreakpointSetCallback(m_thread.ProcessID(), m_sw_single_step_itblock_break_id[i], MachThreadContext_arm::BreakpointHit, (void*)pcInITBlock);
+ m_sw_single_step_itblock_break_count++;
+ }
+ }
+
+ pcInITBlock = nextPCInITBlock;
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP | PD_LOG_VERBOSE, "%s: Set %u IT software single breakpoints.", __FUNCTION__, m_sw_single_step_itblock_break_count);
+
+ }
+
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: next_pc=0x%8.8x (%s)", __FUNCTION__, next_pc, next_pc_is_thumb ? "Thumb" : "ARM");
+
+ if (next_pc & 0x1)
+ {
+ assert(next_pc_is_thumb);
+ }
+
+ if (next_pc_is_thumb)
+ {
+ next_pc &= ~0x1;
+ }
+ else
+ {
+ assert((next_pc & 0x3) == 0);
+ }
+
+ if (!inITBlock || (inITBlock && !m_last_decode_arm.setsFlags) || (lastInITBlock && m_last_decode_arm.branch))
+ {
+ err = KERN_SUCCESS;
+
+#if defined DNB_ARCH_MACH_ARM_DEBUG_SW_STEP
+ m_sw_single_step_next_pc = next_pc;
+ if (next_pc_is_thumb)
+ m_sw_single_step_next_pc |= 1; // Set bit zero if the next PC is expected to be Thumb
+#else
+ const DNBBreakpoint *bp = m_thread.Process()->Breakpoints().FindByAddress(next_pc);
+
+ if (bp == NULL)
+ {
+ m_sw_single_step_break_id = m_thread.Process()->CreateBreakpoint(next_pc, next_pc_is_thumb ? 2 : 4, false, m_thread.GetID());
+ if (!LLDB_BREAK_ID_IS_VALID(m_sw_single_step_break_id))
+ err = KERN_INVALID_ARGUMENT;
+ ProcessMacOSXLog::LogIf(PD_LOG_STEP, "%s: software single step breakpoint with breakID=%d set at 0x%8.8x", __FUNCTION__, m_sw_single_step_break_id, next_pc);
+ }
+#endif
+ }
+
+ return err.GetError();
+}
+
+#endif
+
+MachThreadContext*
+MachThreadContext_arm::Create (const ArchSpec &arch_spec, ThreadMacOSX &thread)
+{
+ return new MachThreadContext_arm(thread);
+}
+
+void
+MachThreadContext_arm::Initialize()
+{
+ ArchSpec arch_spec(CPU_TYPE_ARM, CPU_TYPE_ANY);
+ ProcessMacOSX::AddArchCreateCallback(arch_spec, MachThreadContext_arm::Create);
+}
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.h b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.h
new file mode 100644
index 00000000000..4ec72dfd0d4
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_arm.h
@@ -0,0 +1,63 @@
+//===-- MachThreadContext_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_MachThreadContext_arm_h_
+#define liblldb_MachThreadContext_arm_h_
+
+#include "MachThreadContext.h"
+#include "RegisterContextMach_arm.h"
+
+class ThreadMacOSX;
+
+class MachThreadContext_arm : public MachThreadContext
+{
+public:
+ enum { kMaxNumThumbITBreakpoints = 4 };
+
+ static MachThreadContext*
+ Create (const lldb_private::ArchSpec &arch_spec, ThreadMacOSX &thread);
+
+ static void
+ Initialize();
+
+ MachThreadContext_arm(ThreadMacOSX &thread);
+
+ virtual
+ ~MachThreadContext_arm();
+
+ virtual lldb_private::RegisterContext *
+ CreateRegisterContext (lldb_private::StackFrame *frame) const;
+
+ virtual void
+ InitializeInstance();
+
+ virtual void
+ ThreadWillResume ();
+
+ virtual bool
+ ShouldStop ();
+
+ virtual void
+ RefreshStateAfterStop ();
+
+ static uint32_t
+ GetCPUType ();
+
+protected:
+ kern_return_t
+ EnableHardwareSingleStep (bool enable);
+
+protected:
+ lldb::addr_t m_hw_single_chained_step_addr;
+ uint32_t m_bvr0_reg;
+ uint32_t m_bcr0_reg;
+ uint32_t m_bvr0_save;
+ uint32_t m_bcr0_save;
+};
+#endif // #ifndef liblldb_MachThreadContext_arm_h_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.cpp
new file mode 100644
index 00000000000..ea148a69f41
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.cpp
@@ -0,0 +1,245 @@
+//===-- MachThreadContext_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 (__i386__) || defined (__x86_64__)
+
+
+#include "MachThreadContext_i386.h"
+
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+
+#include "ProcessMacOSX.h"
+#include "ThreadMacOSX.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+MachThreadContext_i386::MachThreadContext_i386 (ThreadMacOSX &thread) :
+ MachThreadContext (thread),
+ m_flags_reg(LLDB_INVALID_REGNUM)
+{
+}
+
+MachThreadContext_i386::~MachThreadContext_i386()
+{
+}
+
+
+MachThreadContext*
+MachThreadContext_i386::Create (const ArchSpec &arch_spec, ThreadMacOSX &thread)
+{
+ return new MachThreadContext_i386(thread);
+}
+
+// Class init function
+void
+MachThreadContext_i386::Initialize()
+{
+ ArchSpec arch_spec("i386");
+ ProcessMacOSX::AddArchCreateCallback(arch_spec, MachThreadContext_i386::Create);
+}
+
+// Instance init function
+void
+MachThreadContext_i386::InitializeInstance()
+{
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx != NULL);
+ m_flags_reg = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+}
+
+
+uint32_t
+MachThreadContext_i386::GetCPUType()
+{
+ return CPU_TYPE_I386;
+}
+
+void
+MachThreadContext_i386::ThreadWillResume()
+{
+ m_thread.GetRegisterContext()->HardwareSingleStep (m_thread.GetState() == eStateStepping);
+}
+
+bool
+MachThreadContext_i386::ShouldStop()
+{
+ return true;
+}
+
+void
+MachThreadContext_i386::RefreshStateAfterStop()
+{
+ m_thread.GetRegisterContext()->HardwareSingleStep (false);
+}
+
+bool
+MachThreadContext_i386::NotifyException (MachException::Data& exc)
+{
+ switch (exc.exc_type)
+ {
+ case EXC_BAD_ACCESS:
+ break;
+ case EXC_BAD_INSTRUCTION:
+ break;
+ case EXC_ARITHMETIC:
+ break;
+ case EXC_EMULATION:
+ break;
+ case EXC_SOFTWARE:
+ break;
+ case EXC_BREAKPOINT:
+ if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2)
+ {
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx);
+ lldb::addr_t pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
+ if (pc != LLDB_INVALID_ADDRESS && pc > 0)
+ {
+ pc -= 1;
+ reg_ctx->SetPC(pc);
+ }
+ return true;
+ }
+ break;
+ case EXC_SYSCALL:
+ break;
+ case EXC_MACH_SYSCALL:
+ break;
+ case EXC_RPC_ALERT:
+ break;
+ }
+ return false;
+}
+
+
+// Set the single step bit in the processor status register.
+//kern_return_t
+//MachThreadContext_i386::EnableHardwareSingleStep (bool enable)
+//{
+// RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+// assert (reg_ctx);
+// Scalar rflags_scalar;
+//
+// if (reg_ctx->ReadRegisterValue (m_flags_reg, rflags_scalar))
+// {
+// Flags rflags(rflags_scalar.UInt());
+// const uint32_t trace_bit = 0x100u;
+// if (enable)
+// {
+// // If the trace bit is already cleared, there is nothing to do
+// if (rflags.IsSet (trace_bit))
+// return KERN_SUCCESS;
+// else
+// rflags.Set (trace_bit);
+// }
+// else
+// {
+// // If the trace bit is already cleared, there is nothing to do
+// if (rflags.IsClear (trace_bit))
+// return KERN_SUCCESS;
+// else
+// rflags.Clear(trace_bit);
+// }
+//
+// rflags_scalar = rflags.GetAllFlagBits();
+// // If the code makes it here we have changes to the GPRs which
+// // we need to write back out, so lets do that.
+// if (reg_ctx->WriteRegisterValue(m_flags_reg, rflags_scalar))
+// return KERN_SUCCESS;
+// }
+// // Return the error code for reading the GPR registers back
+// return KERN_INVALID_ARGUMENT;
+//}
+
+RegisterContext *
+MachThreadContext_i386::CreateRegisterContext (StackFrame *frame) const
+{
+ return new RegisterContextMach_i386(m_thread, frame);
+}
+
+
+size_t
+MachThreadContext_i386::GetStackFrameData(StackFrame *first_frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs)
+{
+ fp_pc_pairs.clear();
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ typedef struct Frame_i386
+ {
+ uint32_t fp;
+ uint32_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx);
+
+ Frame_i386 frame = { reg_ctx->GetFP(0), reg_ctx->GetPC(LLDB_INVALID_ADDRESS) };
+
+ fp_pc_pairs.push_back(std::make_pair(frame.fp, frame.pc));
+
+ 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 (m_thread.GetProcess().ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
+ break;
+
+ if (frame.pc != 0)
+ fp_pc_pairs.push_back(std::make_pair(frame.fp, frame.pc));
+ }
+ if (!fp_pc_pairs.empty())
+ {
+ lldb::addr_t first_frame_pc = fp_pc_pairs.front().second;
+ 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;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ addr_range_ptr = first_frame_sc.symbol->GetAddressRangePtr();
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetPC() == 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 (m_thread.GetProcess().ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
+ {
+ // Construct a correct second frame (we already read the pc for it above
+ frame.fp = fp_pc_pairs.front().first;
+
+ // Insert the frame
+ fp_pc_pairs.insert(fp_pc_pairs.begin()+1, std::make_pair(frame.fp, frame.pc));
+
+ // Correct the fp in the first frame to use the SP
+ fp_pc_pairs.front().first = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+ return fp_pc_pairs.size();
+}
+
+
+#endif // #if defined (__i386__)
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.h b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.h
new file mode 100644
index 00000000000..4bee2e7be8f
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_i386.h
@@ -0,0 +1,57 @@
+//===-- MachThreadContext_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_MachThreadContext_i386_h_
+#define liblldb_MachThreadContext_i386_h_
+
+#if defined (__i386__) || defined (__x86_64__)
+
+#include "MachThreadContext.h"
+#include "RegisterContextMach_i386.h"
+
+class ThreadMacOSX;
+
+class MachThreadContext_i386 : public MachThreadContext
+{
+public:
+ static MachThreadContext* Create(const lldb_private::ArchSpec &arch_spec, ThreadMacOSX &thread);
+
+ // Class init function
+ static void Initialize();
+
+ MachThreadContext_i386(ThreadMacOSX &thread);
+
+ virtual
+ ~MachThreadContext_i386();
+
+ virtual lldb_private::RegisterContext *
+ CreateRegisterContext (lldb_private::StackFrame *frame) const;
+
+ virtual void InitializeInstance();
+ virtual void ThreadWillResume();
+ virtual bool ShouldStop ();
+ virtual void RefreshStateAfterStop();
+
+ virtual bool NotifyException(MachException::Data& exc);
+ virtual size_t GetStackFrameData(lldb_private::StackFrame *first_frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs);
+ static uint32_t GetCPUType();
+
+protected:
+// kern_return_t EnableHardwareSingleStep (bool enable);
+ uint32_t m_flags_reg;
+private:
+ DISALLOW_COPY_AND_ASSIGN (MachThreadContext_i386);
+};
+
+//#if defined (__i386__)
+//typedef MachThreadContext_i386 DNBArch;
+//#endif
+
+#endif // defined (__i386__) || defined (__x86_64__)
+#endif // #ifndef liblldb_MachThreadContext_i386_h_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.cpp
new file mode 100644
index 00000000000..3ee9eb419de
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.cpp
@@ -0,0 +1,255 @@
+//===-- MachThreadContext_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 (__i386__) || defined (__x86_64__)
+
+#include <sys/cdefs.h>
+
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+
+#include "MachThreadContext_x86_64.h"
+#include "ProcessMacOSX.h"
+#include "ThreadMacOSX.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+MachThreadContext_x86_64::MachThreadContext_x86_64(ThreadMacOSX &thread) :
+ MachThreadContext (thread),
+ m_flags_reg(LLDB_INVALID_REGNUM)
+{
+}
+
+MachThreadContext_x86_64::~MachThreadContext_x86_64()
+{
+}
+
+MachThreadContext*
+MachThreadContext_x86_64::Create(const ArchSpec &arch_spec, ThreadMacOSX &thread)
+{
+ return new MachThreadContext_x86_64(thread);
+}
+
+// Class init function
+void
+MachThreadContext_x86_64::Initialize()
+{
+ ArchSpec arch_spec("x86_64");
+ ProcessMacOSX::AddArchCreateCallback(arch_spec, MachThreadContext_x86_64::Create);
+}
+
+// Instance init function
+void
+MachThreadContext_x86_64::InitializeInstance()
+{
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx != NULL);
+ m_flags_reg = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+}
+
+uint32_t
+MachThreadContext_x86_64::GetCPUType()
+{
+ return CPU_TYPE_X86_64;
+}
+
+void
+MachThreadContext_x86_64::ThreadWillResume()
+{
+ m_thread.GetRegisterContext()->HardwareSingleStep (m_thread.GetState() == eStateStepping);
+}
+
+bool
+MachThreadContext_x86_64::ShouldStop()
+{
+ return true;
+}
+
+void
+MachThreadContext_x86_64::RefreshStateAfterStop()
+{
+ m_thread.GetRegisterContext()->HardwareSingleStep (false);
+}
+
+bool
+MachThreadContext_x86_64::NotifyException(MachException::Data& exc)
+{
+ switch (exc.exc_type)
+ {
+ case EXC_BAD_ACCESS:
+ break;
+ case EXC_BAD_INSTRUCTION:
+ break;
+ case EXC_ARITHMETIC:
+ break;
+ case EXC_EMULATION:
+ break;
+ case EXC_SOFTWARE:
+ break;
+ case EXC_BREAKPOINT:
+ if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2)
+ {
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx);
+ lldb::addr_t pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
+ if (pc != LLDB_INVALID_ADDRESS && pc > 0)
+ {
+ pc -= 1;
+ reg_ctx->SetPC(pc);
+ }
+ return true;
+ }
+ break;
+ case EXC_SYSCALL:
+ break;
+ case EXC_MACH_SYSCALL:
+ break;
+ case EXC_RPC_ALERT:
+ break;
+ }
+ return false;
+}
+
+
+// Set the single step bit in the processor status register.
+//kern_return_t
+//MachThreadContext_x86_64::EnableHardwareSingleStep (bool enable)
+//{
+// RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+// assert (reg_ctx);
+// Scalar rflags_scalar;
+//
+// if (reg_ctx->ReadRegisterValue (m_flags_reg, rflags_scalar))
+// {
+// Flags rflags(rflags_scalar.UInt());
+// const uint32_t trace_bit = 0x100u;
+// if (enable)
+// {
+// // If the trace bit is already set, there is nothing to do
+// if (rflags.IsSet (trace_bit))
+// return KERN_SUCCESS;
+// else
+// rflags.Set (trace_bit);
+// }
+// else
+// {
+// // If the trace bit is already cleared, there is nothing to do
+// if (rflags.IsClear (trace_bit))
+// return KERN_SUCCESS;
+// else
+// rflags.Clear(trace_bit);
+// }
+//
+// rflags_scalar = rflags.GetAllFlagBits();
+// // If the code makes it here we have changes to the GPRs which
+// // we need to write back out, so lets do that.
+// if (reg_ctx->WriteRegisterValue(m_flags_reg, rflags_scalar))
+// return KERN_SUCCESS;
+// }
+// // Return the error code for reading the GPR registers back
+// return KERN_INVALID_ARGUMENT;
+//}
+//
+
+//----------------------------------------------------------------------
+// Register information defintions for 32 bit PowerPC.
+//----------------------------------------------------------------------
+
+
+
+RegisterContext *
+MachThreadContext_x86_64::CreateRegisterContext (StackFrame *frame) const
+{
+ return new RegisterContextMach_x86_64(m_thread, frame);
+}
+
+
+//bool
+//MachThreadContext_x86_64::RegisterSetStateIsValid (uint32_t set) const
+//{
+// return m_state.RegisterSetIsCached(set);
+//}
+
+
+size_t
+MachThreadContext_x86_64::GetStackFrameData(StackFrame *first_frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs)
+{
+ fp_pc_pairs.clear();
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ typedef struct Frame_x86_64
+ {
+ uint64_t fp;
+ uint64_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx);
+
+ Frame_x86_64 frame = { reg_ctx->GetFP(0), reg_ctx->GetPC(LLDB_INVALID_ADDRESS) };
+
+ fp_pc_pairs.push_back(std::make_pair(frame.fp, frame.pc));
+ 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 (m_thread.GetProcess().ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
+ break;
+
+ if (frame.pc >= 0x1000)
+ fp_pc_pairs.push_back(std::make_pair(frame.fp, frame.pc));
+ }
+ if (!fp_pc_pairs.empty())
+ {
+ lldb::addr_t first_frame_pc = fp_pc_pairs.front().second;
+ 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;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ addr_range_ptr = first_frame_sc.symbol->GetAddressRangePtr();
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetPC() == 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 (m_thread.GetProcess().ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
+ {
+ // Construct a correct second frame (we already read the pc for it above
+ frame.fp = fp_pc_pairs.front().first;
+
+ // Insert the frame
+ fp_pc_pairs.insert(fp_pc_pairs.begin()+1, std::make_pair(frame.fp, frame.pc));
+
+ // Correct the fp in the first frame to use the SP
+ fp_pc_pairs.front().first = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+ return fp_pc_pairs.size();
+}
+
+
+#endif // #if defined (__i386__) || defined (__x86_64__)
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.h b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.h
new file mode 100644
index 00000000000..45d5a375052
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachThreadContext_x86_64.h
@@ -0,0 +1,72 @@
+//===-- MachThreadContext_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_MachThreadContext_x86_64_h_
+#define liblldb_MachThreadContext_x86_64_h_
+
+#if defined (__i386__) || defined (__x86_64__)
+
+#include "MachThreadContext.h"
+#include "RegisterContextMach_x86_64.h"
+
+class ThreadMacOSX;
+
+class MachThreadContext_x86_64 : public MachThreadContext
+{
+public:
+ static MachThreadContext*
+ Create(const lldb_private::ArchSpec &arch_spec, ThreadMacOSX &thread);
+
+ // Class init function
+ static void
+ Initialize();
+
+ // Instance init function
+ void
+ InitializeInstance();
+
+ MachThreadContext_x86_64 (ThreadMacOSX &thread);
+
+ virtual
+ ~MachThreadContext_x86_64();
+
+ virtual lldb_private::RegisterContext *
+ CreateRegisterContext (lldb_private::StackFrame *frame) const;
+
+ virtual void
+ ThreadWillResume ();
+
+ virtual bool
+ ShouldStop ();
+
+ virtual void
+ RefreshStateAfterStop ();
+
+ virtual bool
+ NotifyException (MachException::Data& exc);
+
+ virtual size_t
+ GetStackFrameData (lldb_private::StackFrame *first_frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs);
+
+ static uint32_t
+ GetCPUType();
+
+protected:
+// kern_return_t EnableHardwareSingleStep (bool enable);
+ uint32_t m_flags_reg;
+private:
+ DISALLOW_COPY_AND_ASSIGN (MachThreadContext_x86_64);
+};
+
+//#if defined (__x86_64__)
+//typedef MachThreadContext_x86_64 DNBArch;
+//#endif
+
+#endif // defined (__i386__) || defined (__x86_64__)
+#endif // #ifndef liblldb_MachThreadContext_x86_64_h_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.cpp
new file mode 100644
index 00000000000..c91af3c3596
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.cpp
@@ -0,0 +1,195 @@
+//===-- MachVMMemory.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachVMMemory.h"
+
+#include <mach/mach_vm.h>
+
+#include "MachVMRegion.h"
+#include "ProcessMacOSXLog.h"
+
+using namespace lldb_private;
+
+MachVMMemory::MachVMMemory() :
+ m_page_size (kInvalidPageSize)
+{
+}
+
+MachVMMemory::~MachVMMemory()
+{
+}
+
+size_t
+MachVMMemory::PageSize(lldb_private::Error &error)
+{
+ if (m_page_size == kInvalidPageSize)
+ {
+ error = ::host_page_size( ::mach_host_self(), &m_page_size);
+ if (error.Fail())
+ m_page_size = 0;
+ }
+
+ if (m_page_size != 0 && m_page_size != kInvalidPageSize)
+ {
+ if (error.Success())
+ error.SetErrorString ("unable to determine page size");
+ }
+ return m_page_size;
+}
+
+size_t
+MachVMMemory::MaxBytesLeftInPage (lldb::addr_t addr, size_t count)
+{
+ Error error;
+ const size_t page_size = PageSize(error);
+ if (page_size > 0)
+ {
+ size_t page_offset = (addr % page_size);
+ size_t bytes_left_in_page = page_size - page_offset;
+ if (count > bytes_left_in_page)
+ count = bytes_left_in_page;
+ }
+ return count;
+}
+
+size_t
+MachVMMemory::Read(task_t task, lldb::addr_t address, void *data, size_t data_count, Error &error)
+{
+ if (data == NULL || data_count == 0)
+ return 0;
+
+ size_t total_bytes_read = 0;
+ lldb::addr_t curr_addr = address;
+ uint8_t *curr_data = (uint8_t*)data;
+ while (total_bytes_read < data_count)
+ {
+ mach_vm_size_t curr_size = MaxBytesLeftInPage(curr_addr, data_count - total_bytes_read);
+ mach_msg_type_number_t curr_bytes_read = 0;
+ vm_offset_t vm_memory = NULL;
+ error = ::mach_vm_read (task, curr_addr, curr_size, &vm_memory, &curr_bytes_read);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY|PD_LOG_VERBOSE);
+
+ if (log || error.Fail())
+ error.PutToLog (log, "::mach_vm_read (task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt => %i)", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read);
+
+ if (error.Success())
+ {
+ if (curr_bytes_read != curr_size)
+ {
+ if (log)
+ error.PutToLog (log, "::mach_vm_read (task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt=>%i) only read %u of %llu bytes", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read, curr_bytes_read, (uint64_t)curr_size);
+ }
+ ::memcpy (curr_data, (void *)vm_memory, curr_bytes_read);
+ ::vm_deallocate (mach_task_self (), vm_memory, curr_bytes_read);
+ total_bytes_read += curr_bytes_read;
+ curr_addr += curr_bytes_read;
+ curr_data += curr_bytes_read;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return total_bytes_read;
+}
+
+
+size_t
+MachVMMemory::Write(task_t task, lldb::addr_t address, const void *data, size_t data_count, Error &error)
+{
+ MachVMRegion vmRegion(task);
+
+ size_t total_bytes_written = 0;
+ lldb::addr_t curr_addr = address;
+ const uint8_t *curr_data = (const uint8_t*)data;
+
+
+ while (total_bytes_written < data_count)
+ {
+ if (vmRegion.GetRegionForAddress(curr_addr))
+ {
+ mach_vm_size_t curr_data_count = data_count - total_bytes_written;
+ mach_vm_size_t region_bytes_left = vmRegion.BytesRemaining(curr_addr);
+ if (region_bytes_left == 0)
+ {
+ break;
+ }
+ if (curr_data_count > region_bytes_left)
+ curr_data_count = region_bytes_left;
+
+ if (vmRegion.SetProtections(curr_addr, curr_data_count, VM_PROT_READ | VM_PROT_WRITE))
+ {
+ size_t bytes_written = WriteRegion(task, curr_addr, curr_data, curr_data_count, error);
+ if (bytes_written <= 0)
+ {
+ // Error should have already be posted by WriteRegion...
+ break;
+ }
+ else
+ {
+ total_bytes_written += bytes_written;
+ curr_addr += bytes_written;
+ curr_data += bytes_written;
+ }
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_MEMORY_PROTECTIONS, "Failed to set read/write protections on region for address: [0x%8.8llx-0x%8.8llx)", (uint64_t)curr_addr, (uint64_t)(curr_addr + curr_data_count));
+ break;
+ }
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_MEMORY_PROTECTIONS, "Failed to get region for address: 0x%8.8llx", (uint64_t)address);
+ break;
+ }
+ }
+
+ return total_bytes_written;
+}
+
+
+size_t
+MachVMMemory::WriteRegion(task_t task, const lldb::addr_t address, const void *data, const size_t data_count, Error &error)
+{
+ if (data == NULL || data_count == 0)
+ return 0;
+
+ size_t total_bytes_written = 0;
+ lldb::addr_t curr_addr = address;
+ const uint8_t *curr_data = (const uint8_t*)data;
+ while (total_bytes_written < data_count)
+ {
+ mach_msg_type_number_t curr_data_count = MaxBytesLeftInPage(curr_addr, data_count - total_bytes_written);
+ error = ::mach_vm_write (task, curr_addr, (pointer_t) curr_data, curr_data_count);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY);
+ if (log || error.Fail())
+ error.PutToLog (log, "::mach_vm_write ( task = 0x%4.4x, addr = 0x%8.8llx, data = %8.8p, dataCnt = %u )", task, (uint64_t)curr_addr, curr_data, curr_data_count);
+
+#if defined (__powerpc__) || defined (__ppc__)
+ vm_machine_attribute_val_t mattr_value = MATTR_VAL_CACHE_FLUSH;
+
+ error = ::vm_machine_attribute (task, curr_addr, curr_data_count, MATTR_CACHE, &mattr_value);
+ if (log || error.Fail())
+ error.Log(log, "::vm_machine_attribute ( task = 0x%4.4x, addr = 0x%8.8llx, size = %u, attr = MATTR_CACHE, mattr_value => MATTR_VAL_CACHE_FLUSH )", task, (uint64_t)curr_addr, curr_data_count);
+#endif
+
+ if (error.Success())
+ {
+ total_bytes_written += curr_data_count;
+ curr_addr += curr_data_count;
+ curr_data += curr_data_count;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return total_bytes_written;
+}
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.h b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.h
new file mode 100644
index 00000000000..866fa369706
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMMemory.h
@@ -0,0 +1,36 @@
+//===-- MachVMMemory.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MachVMMemory_h_
+#define liblldb_MachVMMemory_h_
+
+#include <mach/mach.h>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Error.h"
+
+class MachVMMemory
+{
+public:
+ enum { kInvalidPageSize = ~0 };
+ MachVMMemory();
+ ~MachVMMemory();
+ size_t Read(task_t task, lldb::addr_t address, void *data, size_t data_count, lldb_private::Error &error);
+ size_t Write(task_t task, lldb::addr_t address, const void *data, size_t data_count, lldb_private::Error &error);
+ size_t PageSize(lldb_private::Error &error);
+
+protected:
+ size_t MaxBytesLeftInPage(lldb::addr_t addr, size_t count);
+
+ size_t WriteRegion(task_t task, const lldb::addr_t address, const void *data, const size_t data_count, lldb_private::Error &error);
+ vm_size_t m_page_size;
+};
+
+
+#endif // #ifndef liblldb_MachVMMemory_h_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.cpp
new file mode 100644
index 00000000000..87044fb31b2
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.cpp
@@ -0,0 +1,183 @@
+//===-- MachVMRegion.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 <mach/mach_vm.h>
+#include "MachVMRegion.h"
+#include "ProcessMacOSXLog.h"
+
+using namespace lldb_private;
+
+MachVMRegion::MachVMRegion(task_t task) :
+ m_task(task),
+ m_addr(LLDB_INVALID_ADDRESS),
+ m_err(),
+ m_start(LLDB_INVALID_ADDRESS),
+ m_size(0),
+ m_depth(-1),
+ m_data(),
+ m_curr_protection(0),
+ m_protection_addr(LLDB_INVALID_ADDRESS),
+ m_protection_size(0)
+{
+ memset(&m_data, 0, sizeof(m_data));
+}
+
+MachVMRegion::~MachVMRegion()
+{
+ // Restore any original protections and clear our vars
+ Clear();
+}
+
+void
+MachVMRegion::Clear()
+{
+ RestoreProtections();
+ m_addr = LLDB_INVALID_ADDRESS;
+ m_err.Clear();
+ m_start = LLDB_INVALID_ADDRESS;
+ m_size = 0;
+ m_depth = -1;
+ memset(&m_data, 0, sizeof(m_data));
+ m_curr_protection = 0;
+ m_protection_addr = LLDB_INVALID_ADDRESS;
+ m_protection_size = 0;
+}
+
+bool
+MachVMRegion::SetProtections(mach_vm_address_t addr, mach_vm_size_t size, vm_prot_t prot)
+{
+ if (ContainsAddress(addr))
+ {
+ mach_vm_size_t prot_size = size;
+ mach_vm_address_t end_addr = EndAddress();
+ if (prot_size > (end_addr - addr))
+ prot_size = end_addr - addr;
+
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY_PROTECTIONS);
+ if (prot_size > 0)
+ {
+ if (prot == (m_curr_protection & VM_PROT_ALL))
+ {
+ if (log)
+ log->Printf ("MachVMRegion::%s: protections (%u) already sufficient for task 0x%4.4x at address 0x%8.8llx) ", __FUNCTION__, prot, m_task, (uint64_t)addr);
+ // Protections are already set as requested...
+ return true;
+ }
+ else
+ {
+ m_err = ::mach_vm_protect (m_task, addr, prot_size, 0, prot);
+ if (log || m_err.Fail())
+ m_err.PutToLog(log, "::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)addr, (uint64_t)prot_size, 0, prot);
+ if (m_err.Fail())
+ {
+ // Try again with the ability to create a copy on write region
+ m_err = ::mach_vm_protect (m_task, addr, prot_size, 0, prot | VM_PROT_COPY);
+ if (log || m_err.Fail())
+ m_err.PutToLog(log, "::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)addr, (uint64_t)prot_size, 0, prot | VM_PROT_COPY);
+ }
+ if (m_err.Success())
+ {
+ m_curr_protection = prot;
+ m_protection_addr = addr;
+ m_protection_size = prot_size;
+ return true;
+ }
+ }
+ }
+ else
+ {
+ log->Printf("MachVMRegion::%s: Zero size for task 0x%4.4x at address 0x%8.8llx) ", __FUNCTION__, m_task, (uint64_t)addr);
+ }
+ }
+ return false;
+}
+
+bool
+MachVMRegion::RestoreProtections()
+{
+ if (m_curr_protection != m_data.protection && m_protection_size > 0)
+ {
+ m_err = ::mach_vm_protect (m_task, m_protection_addr, m_protection_size, 0, m_data.protection);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY_PROTECTIONS);
+ if (log || m_err.Fail())
+ m_err.PutToLog(log, "::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)m_protection_addr, (uint64_t)m_protection_size, 0, m_data.protection);
+ if (m_err.Success())
+ {
+ m_protection_size = 0;
+ m_protection_addr = LLDB_INVALID_ADDRESS;
+ m_curr_protection = m_data.protection;
+ return true;
+ }
+ }
+ else
+ {
+ m_err.Clear();
+ return true;
+ }
+
+ return false;
+}
+
+bool
+MachVMRegion::GetRegionForAddress(lldb::addr_t addr)
+{
+ // Restore any original protections and clear our vars
+ Clear();
+ m_addr = addr;
+ m_start = addr;
+ m_depth = 1024;
+ mach_msg_type_number_t info_size = kRegionInfoSize;
+ assert(sizeof(info_size) == 4);
+ m_err = ::mach_vm_region_recurse (m_task, &m_start, &m_size, &m_depth, (vm_region_recurse_info_t)&m_data, &info_size);
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY_PROTECTIONS);
+ if (log || m_err.Fail())
+ m_err.PutToLog(log, "::mach_vm_region_recurse ( task = 0x%4.4x, address => 0x%8.8llx, size => %llu, nesting_depth => %d, info => %p, infoCnt => %d) addr = 0x%8.8llx ", m_task, (uint64_t)m_start, (uint64_t)m_size, m_depth, &m_data, info_size, (uint64_t)addr);
+ if (m_err.Fail())
+ {
+ return false;
+ }
+ else
+ {
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ {
+ log->Printf("info = { prot = %u, "
+ "max_prot = %u, "
+ "inheritance = 0x%8.8x, "
+ "offset = 0x%8.8llx, "
+ "user_tag = 0x%8.8x, "
+ "ref_count = %u, "
+ "shadow_depth = %u, "
+ "ext_pager = %u, "
+ "share_mode = %u, "
+ "is_submap = %d, "
+ "behavior = %d, "
+ "object_id = 0x%8.8x, "
+ "user_wired_count = 0x%4.4x }",
+ m_data.protection,
+ m_data.max_protection,
+ m_data.inheritance,
+ (uint64_t)m_data.offset,
+ m_data.user_tag,
+ m_data.ref_count,
+ m_data.shadow_depth,
+ m_data.external_pager,
+ m_data.share_mode,
+ m_data.is_submap,
+ m_data.behavior,
+ m_data.object_id,
+ m_data.user_wired_count);
+ }
+ }
+
+ m_curr_protection = m_data.protection;
+
+ return true;
+}
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.h b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.h
new file mode 100644
index 00000000000..b12353df823
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/MachVMRegion.h
@@ -0,0 +1,63 @@
+//===-- MachVMRegion.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MachVMRegion_h_
+#define liblldb_MachVMRegion_h_
+
+#include <mach/mach.h>
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Error.h"
+
+class MachVMRegion
+{
+public:
+ MachVMRegion(task_t task);
+ ~MachVMRegion();
+
+ void Clear();
+ mach_vm_address_t StartAddress() const { return m_start; }
+ mach_vm_address_t EndAddress() const { return m_start + m_size; }
+ mach_vm_address_t BytesRemaining(mach_vm_address_t addr) const
+ {
+ if (ContainsAddress(addr))
+ return m_size - (addr - m_start);
+ else
+ return 0;
+ }
+ bool ContainsAddress(mach_vm_address_t addr) const
+ {
+ return addr >= StartAddress() && addr < EndAddress();
+ }
+
+ bool SetProtections(mach_vm_address_t addr, mach_vm_size_t size, vm_prot_t prot);
+ bool RestoreProtections();
+ bool GetRegionForAddress(lldb::addr_t addr);
+protected:
+#if defined (VM_REGION_SUBMAP_SHORT_INFO_COUNT_64)
+ typedef vm_region_submap_short_info_data_64_t RegionInfo;
+ enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 };
+#else
+ typedef vm_region_submap_info_data_64_t RegionInfo;
+ enum { kRegionInfoSize = VM_REGION_SUBMAP_INFO_COUNT_64 };
+#endif
+
+ task_t m_task;
+ mach_vm_address_t m_addr;
+ lldb_private::Error m_err;
+ mach_vm_address_t m_start;
+ mach_vm_size_t m_size;
+ natural_t m_depth;
+ RegionInfo m_data;
+ vm_prot_t m_curr_protection; // The current, possibly modified protections. Original value is saved in m_data.protections.
+ mach_vm_address_t m_protection_addr; // The start address at which protections were changed
+ mach_vm_size_t m_protection_size; // The size of memory that had its protections changed
+
+};
+
+#endif // #ifndef liblldb_MachVMRegion_h_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/ProcessControl-mig.defs b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/ProcessControl-mig.defs
new file mode 100644
index 00000000000..7f16fe13356
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/MacOSX/ProcessControl-mig.defs
@@ -0,0 +1,16 @@
+/*
+ * nub.defs
+ */
+
+/*
+ * DNBConfig.h is autogenerated by a perl script that is run as a build
+ * script in XCode. XCode is responsible for calling the script and setting
+ * the include paths correctly to locate it. The file will exist in the
+ * derived sources directory in the build folder.
+ *
+ */
+
+#include "DNBConfig.h"
+
+
+#include <mach/mach_exc.defs>
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.cpp
new file mode 100644
index 00000000000..3c37b64dc46
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.cpp
@@ -0,0 +1,2228 @@
+//===-- ProcessMacOSX.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 <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <spawn.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <unistd.h>
+
+// C++ Includes
+#include <algorithm>
+#include <map>
+
+// Other libraries and framework includes
+
+#include "lldb/Breakpoint/WatchpointLocation.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+#include "PseudoTerminal.h"
+
+#if defined (__arm__)
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <SpringBoardServices/SpringBoardServer.h>
+#include <SpringBoardServices/SBSWatchdogAssertion.h>
+
+#endif // #if defined (__arm__)
+
+// Project includes
+#include "lldb/Host/Host.h"
+#include "ProcessMacOSX.h"
+#include "ProcessMacOSXLog.h"
+#include "ThreadMacOSX.h"
+
+
+#if 0
+#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_LOG(fmt, ...)
+#endif
+
+#ifndef MACH_PROCESS_USE_POSIX_SPAWN
+#define MACH_PROCESS_USE_POSIX_SPAWN 1
+#endif
+
+
+#if defined (__arm__)
+
+static bool
+IsSBProcess (lldb::pid_t pid)
+{
+ bool opt_runningApps = true;
+ bool opt_debuggable = false;
+
+ CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable));
+ if (sbsAppIDs.get() != NULL)
+ {
+ CFIndex count = ::CFArrayGetCount (sbsAppIDs.get());
+ CFIndex i = 0;
+ for (i = 0; i < count; i++)
+ {
+ CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i);
+
+ // Get the process id for the app (if there is one)
+ lldb::pid_t sbs_pid = LLDB_INVALID_PROCESS_ID;
+ if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &sbs_pid) == TRUE)
+ {
+ if (sbs_pid == pid)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+#endif // #if defined (__arm__)
+
+using namespace lldb;
+using namespace lldb_private;
+//
+//void *
+//ProcessMacOSX::WaitForChildProcessToExit (void *pid_ptr)
+//{
+// const lldb::pid_t pid = *((lldb::user_id_t *)pid_ptr);
+//
+// Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_THREAD);
+//
+// if (log)
+// log->Printf ("ProcessMacOSX::%s (arg = %p) thread starting...", __FUNCTION__, pid_ptr);
+//
+// int status = -1;
+//
+// while (1)
+// {
+// if (log)
+// log->Printf("::waitpid (pid = %i, stat_loc = %p, options = 0)...", pid, &status);
+//
+// lldb::pid_t return_pid = ::waitpid (pid, &status, 0);
+//
+// if (return_pid < 0)
+// {
+// if (log)
+// log->Printf("%s ::waitpid (pid = %i, stat_loc = %p, options = 0) => errno = %i, status = 0x%8.8x", pid, &status, errno, status);
+// break;
+// }
+//
+// bool set_exit_status = false;
+// if (WIFSTOPPED(status))
+// {
+// if (log)
+// log->Printf("::waitpid (pid = %i, stat_loc = %p, options = 0) => return_pid = %i, status = 0x%8.8x (STOPPED)", pid, &status, return_pid, status);
+// }
+// else if (WIFEXITED(status))
+// {
+// set_exit_status = true;
+// if (log)
+// log->Printf("::waitpid (pid = %i, stat_loc = %p, options = 0) => return_pid = %i, status = 0x%8.8x (EXITED)", pid, &status, return_pid, status);
+// }
+// else if (WIFSIGNALED(status))
+// {
+// set_exit_status = true;
+// if (log)
+// log->Printf("::waitpid (pid = %i, stat_loc = %p, options = 0) => return_pid = %i, status = 0x%8.8x (SIGNALED)", pid, &status, return_pid, status);
+// }
+// else
+// {
+// if (log)
+// log->Printf("::waitpid (pid = %i, stat_loc = %p, options = 0) => return_pid = %i, status = 0x%8.8x", pid, &status, return_pid, status);
+// }
+//
+// if (set_exit_status)
+// {
+// // Try and deliver the news to the process if it is still around
+// TargetSP target_sp(TargetList::SharedList().FindTargetWithProcessID (return_pid));
+// if (target_sp.get())
+// {
+// ProcessMacOSX *process = dynamic_cast<ProcessMacOSX*>(target_sp->GetProcess().get());
+// if (process)
+// {
+// process->SetExitStatus (status);
+// if (log)
+// log->Printf("Setting exit status of %i to 0x%8.8x", pid, status);
+// process->Task().ShutDownExceptionThread();
+// }
+// }
+// // Break out of the loop and return.
+// break;
+// }
+// }
+//
+// if (log)
+// log->Printf ("ProcessMacOSX::%s (arg = %p) thread exiting...", __FUNCTION__, pid_ptr);
+//
+// return NULL;
+//}
+//
+
+const char *
+ProcessMacOSX::GetPluginNameStatic()
+{
+ return "process.macosx";
+}
+
+const char *
+ProcessMacOSX::GetPluginDescriptionStatic()
+{
+ return "Native MacOSX user process debugging plug-in.";
+}
+
+void
+ProcessMacOSX::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessMacOSX::CreateInstance);
+}
+
+
+Process*
+ProcessMacOSX::CreateInstance (Target &target, Listener &listener)
+{
+ ProcessMacOSX::Initialize();
+
+ return new ProcessMacOSX (target, listener);
+}
+
+bool
+ProcessMacOSX::CanDebug(Target &target)
+{
+ // 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();
+ return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessMacOSX constructor
+//----------------------------------------------------------------------
+ProcessMacOSX::ProcessMacOSX(Target& target, Listener &listener) :
+ Process (target, listener),
+ m_dynamic_loader_ap (),
+// m_wait_thread (LLDB_INVALID_HOST_THREAD),
+ m_byte_order (eByteOrderHost),
+ m_stdio_ours (false),
+ m_child_stdin (-1),
+ m_child_stdout (-1),
+ m_child_stderr (-1),
+ m_task (this),
+ m_flags (eFlagsNone),
+ m_stdio_thread (LLDB_INVALID_HOST_THREAD),
+ m_stdio_mutex (Mutex::eMutexTypeRecursive),
+ m_stdout_data (),
+ m_exception_messages (),
+ m_exception_messages_mutex (Mutex::eMutexTypeRecursive),
+ m_arch_spec ()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessMacOSX::~ProcessMacOSX()
+{
+// m_mach_process.UnregisterNotificationCallbacks (this);
+ Clear();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+const char *
+ProcessMacOSX::GetPluginName()
+{
+ return "Process debugging plug-in for MacOSX";
+}
+
+const char *
+ProcessMacOSX::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessMacOSX::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ProcessMacOSX::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+ strm->Printf("The following arguments can be supplied to the 'log %s' command:\n", GetShortPluginName());
+ strm->PutCString("\tverbose - enable verbose logging\n");
+ strm->PutCString("\tprocess - enable process logging\n");
+ strm->PutCString("\tthread - enable thread logging\n");
+ strm->PutCString("\texceptions - enable exception logging\n");
+ strm->PutCString("\tdynamic - enable DynamicLoader logging\n");
+ strm->PutCString("\tmemory-calls - enable memory read and write call logging\n");
+ strm->PutCString("\tmemory-data-short - log short memory read and write byte data\n");
+ strm->PutCString("\tmemory-data-long - log all memory read and write byte data\n");
+ strm->PutCString("\tmemory-protections - log memory protection calls\n");
+ strm->PutCString("\tbreakpoints - log breakpoint calls\n");
+ strm->PutCString("\twatchpoints - log watchpoint calls\n");
+ strm->PutCString("\tevents - log event and event queue status\n");
+ strm->PutCString("\tstep - log step related activity\n");
+ strm->PutCString("\ttask - log task functions\n");
+}
+
+Error
+ProcessMacOSX::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ProcessMacOSX::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessMacOSX::DoLaunch
+(
+ Module* module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path
+)
+{
+// ::LogSetBitMask (PD_LOG_DEFAULT);
+// ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
+// ::LogSetLogFile ("/dev/stdout");
+
+ Error error;
+ ObjectFile * object_file = module->GetObjectFile();
+ if (object_file)
+ {
+ ArchSpec arch_spec(module->GetArchitecture());
+
+ // Set our user ID to our process ID.
+ SetID (LaunchForDebug(argv[0], argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, eLaunchDefault, error));
+ }
+ else
+ {
+ // Set our user ID to an invalid process ID.
+ SetID (LLDB_INVALID_PROCESS_ID);
+ error.SetErrorToGenericError ();
+ error.SetErrorStringWithFormat("Failed to get object file from '%s' for arch %s.\n", module->GetFileSpec().GetFilename().AsCString(), module->GetArchitecture().AsCString());
+ }
+
+ // Return the process ID we have
+ return error;
+}
+
+Error
+ProcessMacOSX::DoAttach (lldb::pid_t attach_pid)
+{
+ Error error;
+
+ // Clear out and clean up from any current state
+ Clear();
+ // HACK: require arch be set correctly at the target level until we can
+ // figure out a good way to determine the arch of what we are attaching to
+ m_arch_spec = m_target.GetArchitecture();
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+ if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ SetPrivateState (eStateAttaching);
+ SetID(attach_pid);
+ // Let ourselves know we are going to be using SBS if the correct flag bit is set...
+#if defined (__arm__)
+ if (IsSBProcess(pid))
+ m_flags |= eFlagsUsingSBS;
+#endif
+
+ if (Task().GetTaskPortForProcessID(error) == TASK_NULL)
+ {
+ if (log)
+ log->Printf ("error attaching to pid %i: %s", GetID(), error.AsCString());
+
+ }
+ else
+ {
+ Task().StartExceptionThread(error);
+
+ if (error.Success())
+ {
+ errno = 0;
+ if (::ptrace (PT_ATTACHEXC, GetID(), 0, 0) == 0)
+ {
+ m_flags.Set (eFlagsAttached);
+ // Sleep a bit to let the exception get received and set our process status
+ // to stopped.
+ ::usleep(250000);
+
+ if (log)
+ log->Printf ("successfully attached to pid %d", GetID());
+ return error;
+ }
+ else
+ {
+ error.SetErrorToErrno();
+ if (log)
+ log->Printf ("error: failed to attach to pid %d", GetID());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("error: failed to start exception thread for pid %d: %s", GetID(), error.AsCString());
+ }
+
+ }
+ }
+ SetID (LLDB_INVALID_PROCESS_ID);
+ if (error.Success())
+ error.SetErrorStringWithFormat ("failed to attach to pid %d", attach_pid);
+ return error;
+}
+
+Error
+ProcessMacOSX::WillLaunchOrAttach ()
+{
+ Error error;
+ // TODO: this is hardcoded for macosx right now. We need this to be more dynamic
+ m_dynamic_loader_ap.reset(DynamicLoader::FindPlugin(this, "dynamic-loader.macosx-dyld"));
+
+ if (m_dynamic_loader_ap.get() == NULL)
+ error.SetErrorString("unable to find the dynamic loader named 'dynamic-loader.macosx-dyld'");
+
+ return error;
+}
+
+
+Error
+ProcessMacOSX::WillLaunch (Module* module)
+{
+ return WillLaunchOrAttach ();
+}
+
+void
+ProcessMacOSX::DidLaunchOrAttach ()
+{
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ m_dynamic_loader_ap.reset();
+ }
+ else
+ {
+ Module * exe_module = GetTarget().GetExecutableModule ().get();
+ assert (exe_module);
+
+ m_arch_spec = exe_module->GetArchitecture();
+ assert (m_arch_spec.IsValid());
+
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ assert (exe_objfile);
+
+ m_byte_order = exe_objfile->GetByteOrder();
+ assert (m_byte_order != eByteOrderInvalid);
+ // Install a signal handler so we can catch when our child process
+ // dies and set the exit status correctly.
+
+ Host::StartMonitoringChildProcess (Process::SetProcessExitStatus, NULL, GetID(), false);
+
+ if (m_arch_spec == ArchSpec("arm"))
+ {
+ // On ARM we want the actual target triple of the OS to get the
+ // most capable ARM slice for the process. Since this plug-in is
+ // only used for doing native debugging this will work.
+ m_target_triple = Host::GetTargetTriple();
+ }
+ else
+ {
+ // We want the arch of the process, and the vendor and OS from the
+ // host OS.
+ StreamString triple;
+
+ triple.Printf("%s-%s-%s",
+ m_arch_spec.AsCString(),
+ Host::GetVendorString().AsCString("apple"),
+ Host::GetOSString().AsCString("darwin"));
+
+ m_target_triple.SetCString(triple.GetString().c_str());
+ }
+ }
+}
+
+void
+ProcessMacOSX::DidLaunch ()
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSX::DidLaunch()");
+ DidLaunchOrAttach ();
+ if (m_dynamic_loader_ap.get())
+ m_dynamic_loader_ap->DidLaunch();
+}
+
+void
+ProcessMacOSX::DidAttach ()
+{
+ DidLaunchOrAttach ();
+ if (m_dynamic_loader_ap.get())
+ m_dynamic_loader_ap->DidAttach();
+}
+
+Error
+ProcessMacOSX::WillAttach (lldb::pid_t pid)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessMacOSX::DoResume ()
+{
+ Error error;
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSX::Resume()");
+ const StateType state = m_private_state.GetValue();
+
+ if (CanResume(state))
+ {
+ error = PrivateResume(LLDB_INVALID_THREAD_ID);
+ }
+ else if (state == eStateRunning)
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "Resume() - task 0x%x is running, ignoring...", Task().GetTaskPort());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("task 0x%x can't continue, ignoring...", Task().GetTaskPort());
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "Resume() - task 0x%x can't continue, ignoring...", Task().GetTaskPort());
+ }
+ return error;
+}
+
+size_t
+ProcessMacOSX::GetSoftwareBreakpointTrapOpcode (BreakpointSite* bp_site)
+{
+ const uint8_t *trap_opcode = NULL;
+ uint32_t trap_opcode_size = 0;
+
+ static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 };
+ //static const uint8_t g_thumb_breakpooint_opcode[] = { 0xFE, 0xDE };
+ static const uint8_t g_ppc_breakpoint_opcode[] = { 0x7F, 0xC0, 0x00, 0x08 };
+ static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC };
+
+ switch (m_arch_spec.GetCPUType())
+ {
+ case CPU_TYPE_ARM:
+ // TODO: fill this in for ARM. We need to dig up the symbol for
+ // the address in the breakpoint locaiton and figure out if it is
+ // an ARM or Thumb breakpoint.
+ trap_opcode = g_arm_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
+ break;
+
+ case CPU_TYPE_POWERPC:
+ case CPU_TYPE_POWERPC64:
+ trap_opcode = g_ppc_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_ppc_breakpoint_opcode);
+ break;
+
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ trap_opcode = g_i386_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_i386_breakpoint_opcode);
+ break;
+
+ default:
+ assert(!"Unhandled architecture in ProcessMacOSX::GetSoftwareBreakpointTrapOpcode()");
+ return 0;
+ }
+
+ if (trap_opcode && trap_opcode_size)
+ {
+ if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+ }
+ return 0;
+}
+uint32_t
+ProcessMacOSX::UpdateThreadListIfNeeded ()
+{
+ // locker will keep a mutex locked until it goes out of scope
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ProcessMacOSX::%s (pid = %4.4x)", __FUNCTION__, GetID());
+
+ const uint32_t stop_id = GetStopID();
+ if (m_thread_list.GetSize(false) == 0 || stop_id != m_thread_list.GetStopID())
+ {
+ // Update the thread list's stop id immediately so we don't recurse into this function.
+ thread_array_t thread_list = NULL;
+ mach_msg_type_number_t thread_list_count = 0;
+ task_t task = Task().GetTaskPort();
+ Error err(::task_threads (task, &thread_list, &thread_list_count), eErrorTypeMachKernel);
+
+ if (log || err.Fail())
+ err.PutToLog(log, "::task_threads ( task = 0x%4.4x, thread_list => %p, thread_list_count => %u )", task, thread_list, thread_list_count);
+
+ if (err.GetError() == KERN_SUCCESS && thread_list_count > 0)
+ {
+ ThreadList curr_thread_list (this);
+ curr_thread_list.SetStopID(stop_id);
+
+ size_t idx;
+ // Iterator through the current thread list and see which threads
+ // we already have in our list (keep them), which ones we don't
+ // (add them), and which ones are not around anymore (remove them).
+ for (idx = 0; idx < thread_list_count; ++idx)
+ {
+ const lldb::tid_t tid = thread_list[idx];
+ ThreadSP thread_sp(GetThreadList().FindThreadByID (tid, false));
+ if (thread_sp.get() == NULL)
+ thread_sp.reset (new ThreadMacOSX (*this, tid));
+ curr_thread_list.AddThread(thread_sp);
+ }
+
+ m_thread_list = curr_thread_list;
+
+ // Free the vm memory given to us by ::task_threads()
+ vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (lldb::tid_t));
+ ::vm_deallocate (::mach_task_self(),
+ (vm_address_t)thread_list,
+ thread_list_size);
+ }
+ }
+ return GetThreadList().GetSize(false);
+}
+
+
+void
+ProcessMacOSX::RefreshStateAfterStop ()
+{
+ // If we are attaching, let our dynamic loader plug-in know so it can get
+ // an initial list of shared libraries.
+
+ // We must be attaching if we don't already have a valid architecture
+ if (!m_arch_spec.IsValid())
+ {
+ Module *exe_module = GetTarget().GetExecutableModule().get();
+ if (exe_module)
+ m_arch_spec = exe_module->GetArchitecture();
+ }
+ // Discover new threads:
+ UpdateThreadListIfNeeded ();
+
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ m_thread_list.RefreshStateAfterStop();
+
+ // Let each thread know of any exceptions
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ task_t task = Task().GetTaskPort();
+ size_t i;
+ for (i=0; i<m_exception_messages.size(); ++i)
+ {
+ // Let the thread list figure use the ProcessMacOSX to forward all exceptions
+ // on down to each thread.
+ if (m_exception_messages[i].state.task_port == task)
+ {
+ ThreadSP thread_sp(m_thread_list.FindThreadByID(m_exception_messages[i].state.thread_port));
+ if (thread_sp.get())
+ {
+ ThreadMacOSX *macosx_thread = (ThreadMacOSX *)thread_sp.get();
+ macosx_thread->NotifyException (m_exception_messages[i].state);
+ }
+ }
+ if (log)
+ m_exception_messages[i].PutToLog(log);
+ }
+
+}
+
+Error
+ProcessMacOSX::DoHalt ()
+{
+ return Signal (SIGSTOP);
+}
+
+Error
+ProcessMacOSX::WillDetach ()
+{
+ Error error;
+ const StateType state = m_private_state.GetValue();
+
+ if (IsRunning(state))
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Process must be stopped in order to detach.");
+ }
+ return error;
+}
+
+Error
+ProcessMacOSX::DoSIGSTOP (bool clear_all_breakpoints)
+{
+ Error error;
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_PROCESS);
+
+ if (log)
+ log->Printf ("ProcessMacOSX::DoSIGSTOP()");
+ EventSP event_sp;
+ TimeValue timeout_time;
+
+ StateType state = m_private_state.GetValue();
+
+ lldb::pid_t pid = GetID();
+
+ if (IsRunning(state))
+ {
+ // If our process is running, we need to SIGSTOP it so we can detach.
+ if (log)
+ log->Printf ("ProcessMacOSX::DoDestroy() - kill (%i, SIGSTOP)", pid);
+
+ // Send the SIGSTOP and wait a few seconds for it to stop
+
+ // Pause the Private State Thread so it doesn't intercept the events we need to wait for.
+ PausePrivateStateThread();
+
+ m_thread_list.DiscardThreadPlans();
+
+ // First jettison all the current thread plans, since we want to make sure it
+ // really just stops.
+
+ if (::kill (pid, SIGSTOP) == 0)
+ error.Clear();
+ else
+ error.SetErrorToErrno();
+
+ if (error.Fail())
+ error.PutToLog(log, "::kill (pid = %i, SIGSTOP)", pid);
+
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(2);
+
+ state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp);
+
+ // Resume the private state thread at this point.
+ ResumePrivateStateThread();
+
+ if (!StateIsStoppedState (state))
+ {
+ if (log)
+ log->Printf("ProcessMacOSX::DoSIGSTOP() failed to stop after sending SIGSTOP");
+ return error;
+ }
+ if (clear_all_breakpoints)
+ GetTarget().DisableAllBreakpoints();
+ }
+ else if (!HasExited(state))
+ {
+ if (clear_all_breakpoints)
+ GetTarget().DisableAllBreakpoints();
+
+// const uint32_t num_threads = GetNumThreads();
+// for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx)
+// {
+// Thread *thread = GetThreadAtIndex(thread_idx);
+// thread->SetResumeState(eStateRunning);
+// if (thread_idx == 0)
+// thread->SetResumeSignal(SIGSTOP);
+// }
+
+ // Our process was stopped, so resume it and then SIGSTOP it so we can
+ // detach.
+ // But discard all the thread plans first, so we don't keep going because we
+ // are in mid-plan.
+
+ // Pause the Private State Thread so it doesn't intercept the events we need to wait for.
+ PausePrivateStateThread();
+
+ m_thread_list.DiscardThreadPlans();
+
+ if (::kill (pid, SIGSTOP) == 0)
+ error.Clear();
+ else
+ error.SetErrorToErrno();
+
+ if (log || error.Fail())
+ error.PutToLog(log, "ProcessMacOSX::DoSIGSTOP() ::kill (pid = %i, SIGSTOP)", pid);
+
+ error = PrivateResume(LLDB_INVALID_THREAD_ID);
+
+ // Wait a few seconds for our process to resume
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(2);
+ state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp);
+
+ // Make sure the process resumed
+ if (StateIsStoppedState (state))
+ {
+ if (log)
+ log->Printf ("ProcessMacOSX::DoSIGSTOP() couldn't resume process, state = %s", StateAsCString(state));
+ error.SetErrorStringWithFormat("ProcessMacOSX::DoSIGSTOP() couldn't resume process, state = %s", StateAsCString(state));
+ }
+ else
+ {
+ // Send the SIGSTOP and wait a few seconds for it to stop
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(2);
+ state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp);
+ if (!StateIsStoppedState (state))
+ {
+ if (log)
+ log->Printf("ProcessMacOSX::DoSIGSTOP() failed to stop after sending SIGSTOP");
+ error.SetErrorString("ProcessMacOSX::DoSIGSTOP() failed to stop after sending SIGSTOP");
+ }
+ }
+ // Resume the private state thread at this point.
+ ResumePrivateStateThread();
+ }
+
+ return error;
+}
+
+Error
+ProcessMacOSX::DoDestroy ()
+{
+ Error error;
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessMacOSX::DoDestroy()");
+
+ error = DoSIGSTOP (true);
+ if (error.Success())
+ {
+ StopSTDIOThread(true);
+
+ if (log)
+ log->Printf ("ProcessMacOSX::DoDestroy() DoSIGSTOP succeeded");
+ const StateType state = m_private_state.GetValue();
+ // Scope for "locker" so we can reply to all of our exceptions (the SIGSTOP
+ // exception).
+ {
+ Mutex::Locker locker(m_exception_messages_mutex);
+ ReplyToAllExceptions();
+ }
+ if (log)
+ log->Printf ("ProcessMacOSX::DoDestroy() replied to all exceptions");
+
+ // Shut down the exception thread and cleanup our exception remappings
+ Task().ShutDownExceptionThread();
+
+ if (log)
+ log->Printf ("ProcessMacOSX::DoDestroy() exception thread has been shutdown");
+
+ if (!HasExited(state))
+ {
+ lldb::pid_t pid = GetID();
+
+ // Detach from our process while we are stopped.
+ errno = 0;
+
+ // Detach from our process
+ ::ptrace (PT_KILL, pid, 0, 0);
+
+ error.SetErrorToErrno();
+
+ if (log || error.Fail())
+ error.PutToLog (log, "::ptrace (PT_KILL, %u, 0, 0)", pid);
+
+ // Resume our task and let the SIGKILL do its thing. The thread named
+ // "ProcessMacOSX::WaitForChildProcessToExit(void*)" will catch the
+ // process exiting, so we don't need to set our state to exited in this
+ // function.
+ Task().Resume();
+ }
+
+ // NULL our task out as we have already retored all exception ports
+ Task().Clear();
+
+ // Clear out any notion of the process we once were
+ Clear();
+ }
+ return error;
+}
+
+ByteOrder
+ProcessMacOSX::GetByteOrder () const
+{
+ return m_byte_order;
+}
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessMacOSX::IsAlive ()
+{
+ return MachTask::IsValid (Task().GetTaskPort());
+}
+
+lldb::addr_t
+ProcessMacOSX::GetImageInfoAddress()
+{
+ return Task().GetDYLDAllImageInfosAddress();
+}
+
+DynamicLoader *
+ProcessMacOSX::GetDynamicLoader()
+{
+ return m_dynamic_loader_ap.get();
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+
+size_t
+ProcessMacOSX::DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error& error)
+{
+ return Task().ReadMemory(addr, buf, size, error);
+}
+
+size_t
+ProcessMacOSX::DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, Error& error)
+{
+ return Task().WriteMemory(addr, buf, size, error);
+}
+
+lldb::addr_t
+ProcessMacOSX::DoAllocateMemory (size_t size, uint32_t permissions, Error& error)
+{
+ return Task().AllocateMemory (size, permissions, error);
+}
+
+Error
+ProcessMacOSX::DoDeallocateMemory (lldb::addr_t ptr)
+{
+ return Task().DeallocateMemory (ptr);
+}
+
+//------------------------------------------------------------------
+// Process STDIO
+//------------------------------------------------------------------
+
+size_t
+ProcessMacOSX::GetSTDOUT (char *buf, size_t buf_size, Error &error)
+{
+ error.Clear();
+ Mutex::Locker locker(m_stdio_mutex);
+ size_t bytes_available = m_stdout_data.size();
+ if (bytes_available > 0)
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSX::%s (&%p[%u]) ...", __FUNCTION__, buf, buf_size);
+ if (bytes_available > buf_size)
+ {
+ memcpy(buf, m_stdout_data.data(), buf_size);
+ m_stdout_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ }
+ else
+ {
+ memcpy(buf, m_stdout_data.data(), bytes_available);
+ m_stdout_data.clear();
+
+ //ResetEventBits(eBroadcastBitSTDOUT);
+ }
+ }
+ return bytes_available;
+}
+
+size_t
+ProcessMacOSX::GetSTDERR (char *buf, size_t buf_size, Error &error)
+{
+ error.Clear();
+ return 0;
+}
+
+size_t
+ProcessMacOSX::PutSTDIN (const char *buf, size_t buf_size, Error &error)
+{
+ if (m_child_stdin == -1)
+ {
+ error.SetErrorString ("Invalid child stdin handle.");
+ }
+ else
+ {
+ ssize_t bytes_written = ::write (m_child_stdin, buf, buf_size);
+ if (bytes_written == -1)
+ error.SetErrorToErrno();
+ else
+ {
+ error.Clear();
+ return bytes_written;
+ }
+ }
+ return 0;
+}
+
+Error
+ProcessMacOSX::EnableBreakpoint (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+ const lldb::addr_t addr = bp_site->GetLoadAddress();
+ const lldb::user_id_t site_id = bp_site->GetID();
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("ProcessMacOSX::EnableBreakpoint (site_id = %d) addr = 0x%8.8llx", site_id, (uint64_t)addr);
+
+ if (bp_site->IsEnabled())
+ {
+ if (log)
+ log->Printf ("ProcessMacOSX::EnableBreakpoint (site_id = %d) addr = 0x%8.8llx -- SUCCESS (already enabled)", site_id, (uint64_t)addr);
+ return error;
+ }
+
+ if (bp_site->HardwarePreferred())
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(bp_site->GetThreadID()).get();
+ if (thread)
+ {
+ bp_site->SetHardwareIndex (thread->SetHardwareBreakpoint(bp_site));
+ if (bp_site->IsHardware())
+ {
+ bp_site->SetEnabled(true);
+ return error;
+ }
+ }
+ }
+
+ // Just let lldb::Process::EnableSoftwareBreakpoint() handle everything...
+ return EnableSoftwareBreakpoint (bp_site);
+}
+
+Error
+ProcessMacOSX::DisableBreakpoint (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+ const lldb::addr_t addr = bp_site->GetLoadAddress();
+ const lldb::user_id_t site_id = bp_site->GetID();
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("ProcessMacOSX::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx", site_id, (uint64_t)addr);
+
+ if (bp_site->IsHardware())
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(bp_site->GetThreadID()).get();
+ if (thread)
+ {
+ if (thread->ClearHardwareBreakpoint(bp_site))
+ {
+ bp_site->SetEnabled(false);
+ if (log)
+ log->Printf ("ProcessMacOSX::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx -- SUCCESS (hardware)", site_id, (uint64_t)addr);
+ return error;
+ }
+ }
+ error.SetErrorString("hardware breakpoints are no supported");
+ return error;
+ }
+
+ // Just let lldb::Process::EnableSoftwareBreakpoint() handle everything...
+ return DisableSoftwareBreakpoint (bp_site);
+}
+
+Error
+ProcessMacOSX::EnableWatchpoint (WatchpointLocation *wp)
+{
+ Error error;
+ if (wp)
+ {
+ lldb::user_id_t watchID = wp->GetID();
+ lldb::addr_t addr = wp->GetLoadAddress();
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_WATCHPOINTS);
+ if (log)
+ log->Printf ("ProcessMacOSX::EnableWatchpoint(watchID = %d)", watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessMacOSX::EnableWatchpoint(watchID = %d) addr = 0x%8.8llx: watchpoint already enabled.", watchID, (uint64_t)addr);
+ return error;
+ }
+ else
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(wp->GetThreadID()).get();
+ if (thread)
+ {
+ wp->SetHardwareIndex (thread->SetHardwareWatchpoint (wp));
+ if (wp->IsHardware ())
+ {
+ wp->SetEnabled(true);
+ return error;
+ }
+ }
+ else
+ {
+ error.SetErrorString("Watchpoints currently only support thread specific watchpoints.");
+ }
+ }
+ }
+ return error;
+}
+
+Error
+ProcessMacOSX::DisableWatchpoint (WatchpointLocation *wp)
+{
+ Error error;
+ if (wp)
+ {
+ lldb::user_id_t watchID = wp->GetID();
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_WATCHPOINTS);
+
+ lldb::addr_t addr = wp->GetLoadAddress();
+ if (log)
+ log->Printf ("ProcessMacOSX::DisableWatchpoint (watchID = %d) addr = 0x%8.8llx", watchID, (uint64_t)addr);
+
+ if (wp->IsHardware())
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(wp->GetThreadID()).get();
+ if (thread)
+ {
+ if (thread->ClearHardwareWatchpoint (wp))
+ {
+ wp->SetEnabled(false);
+ if (log)
+ log->Printf ("ProcessMacOSX::Disablewatchpoint (watchID = %d) addr = 0x%8.8llx (hardware) => success", watchID, (uint64_t)addr);
+ return error;
+ }
+ }
+ }
+ // TODO: clear software watchpoints if we implement them
+ error.SetErrorToGenericError();
+ }
+ else
+ {
+ error.SetErrorString("Watchpoint location argument was NULL.");
+ }
+ return error;
+}
+
+
+static ProcessMacOSX::CreateArchCalback
+ArchCallbackMap(const ArchSpec& arch_spec, ProcessMacOSX::CreateArchCalback callback, bool add )
+{
+ // We must wrap the "g_arch_map" file static in a function to avoid
+ // any global constructors so we don't get a build verification error
+ typedef std::multimap<ArchSpec, ProcessMacOSX::CreateArchCalback> ArchToProtocolMap;
+ static ArchToProtocolMap g_arch_map;
+
+ if (add)
+ {
+ g_arch_map.insert(std::make_pair(arch_spec, callback));
+ return callback;
+ }
+ else
+ {
+ ArchToProtocolMap::const_iterator pos = g_arch_map.find(arch_spec);
+ if (pos != g_arch_map.end())
+ {
+ return pos->second;
+ }
+ }
+ return NULL;
+}
+
+void
+ProcessMacOSX::AddArchCreateCallback(const ArchSpec& arch_spec, CreateArchCalback callback)
+{
+ ArchCallbackMap (arch_spec, callback, true);
+}
+
+ProcessMacOSX::CreateArchCalback
+ProcessMacOSX::GetArchCreateCallback()
+{
+ return ArchCallbackMap (m_arch_spec, NULL, false);
+}
+
+void
+ProcessMacOSX::Clear()
+{
+ // Clear any cached thread list while the pid and task are still valid
+
+ Task().Clear();
+ // Now clear out all member variables
+ CloseChildFileDescriptors();
+
+ m_flags = eFlagsNone;
+ m_thread_list.Clear();
+ {
+ Mutex::Locker locker(m_exception_messages_mutex);
+ m_exception_messages.clear();
+ }
+
+}
+
+bool
+ProcessMacOSX::StartSTDIOThread()
+{
+ // If we created and own the child STDIO file handles, then we track the
+ // STDIO ourselves, else we let whomever owns these file handles track
+ // the IO themselves.
+ if (m_stdio_ours)
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSX::%s ( )", __FUNCTION__);
+ // Create the thread that watches for the child STDIO
+ m_stdio_thread = Host::ThreadCreate ("<lldb.process.process-macosx.stdio>", ProcessMacOSX::STDIOThread, this, NULL);
+ return m_stdio_thread != LLDB_INVALID_HOST_THREAD;
+ }
+ return false;
+}
+
+
+void
+ProcessMacOSX::StopSTDIOThread(bool close_child_fds)
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSX::%s ( )", __FUNCTION__);
+ // Stop the stdio thread
+ if (m_stdio_thread != LLDB_INVALID_HOST_THREAD)
+ {
+ Host::ThreadCancel (m_stdio_thread, NULL);
+ thread_result_t result = NULL;
+ Host::ThreadJoin (m_stdio_thread, &result, NULL);
+ if (close_child_fds)
+ CloseChildFileDescriptors();
+ else
+ {
+ // We may have given up control of these file handles, so just
+ // set them to invalid values so the STDIO thread can exit when
+ // we interrupt it with pthread_cancel...
+ m_child_stdin = -1;
+ m_child_stdout = -1;
+ m_child_stderr = -1;
+ }
+ }
+}
+
+
+void *
+ProcessMacOSX::STDIOThread(void *arg)
+{
+ ProcessMacOSX *proc = (ProcessMacOSX*) arg;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessMacOSX::%s (arg = %p) thread starting...", __FUNCTION__, arg);
+
+ // We start use a base and more options so we can control if we
+ // are currently using a timeout on the mach_msg. We do this to get a
+ // bunch of related exceptions on our exception port so we can process
+ // then together. When we have multiple threads, we can get an exception
+ // per thread and they will come in consecutively. The main thread loop
+ // will start by calling mach_msg to without having the MACH_RCV_TIMEOUT
+ // flag set in the options, so we will wait forever for an exception on
+ // our exception port. After we get one exception, we then will use the
+ // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current
+ // exceptions for our process. After we have received the last pending
+ // exception, we will get a timeout which enables us to then notify
+ // our main thread that we have an exception bundle avaiable. We then wait
+ // for the main thread to tell this exception thread to start trying to get
+ // exceptions messages again and we start again with a mach_msg read with
+ // infinite timeout.
+ Error err;
+ int stdout_fd = proc->GetStdoutFileDescriptor();
+ int stderr_fd = proc->GetStderrFileDescriptor();
+ if (stdout_fd == stderr_fd)
+ stderr_fd = -1;
+
+ while (stdout_fd >= 0 || stderr_fd >= 0)
+ {
+ //::pthread_testcancel ();
+
+ fd_set read_fds;
+ FD_ZERO (&read_fds);
+ if (stdout_fd >= 0)
+ FD_SET (stdout_fd, &read_fds);
+ if (stderr_fd >= 0)
+ FD_SET (stderr_fd, &read_fds);
+ int nfds = std::max<int>(stdout_fd, stderr_fd) + 1;
+
+ int num_set_fds = select (nfds, &read_fds, NULL, NULL, NULL);
+ if (log)
+ log->Printf("select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
+
+ if (num_set_fds < 0)
+ {
+ int select_errno = errno;
+ if (log)
+ {
+ err.SetError (select_errno, eErrorTypePOSIX);
+ err.LogIfError(log, "select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
+ }
+
+ switch (select_errno)
+ {
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to allocate the requested number of file descriptors, or we have non-blocking IO
+ break;
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ return NULL;
+ break;
+ case EINTR: // A signal was delivered before the time limit expired and before any of the selected events occurred.
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
+ break;
+ }
+ }
+ else if (num_set_fds == 0)
+ {
+ }
+ else
+ {
+ char s[1024];
+ s[sizeof(s)-1] = '\0'; // Ensure we have NULL termination
+ int bytes_read = 0;
+ if (stdout_fd >= 0 && FD_ISSET (stdout_fd, &read_fds))
+ {
+ do
+ {
+ bytes_read = ::read (stdout_fd, s, sizeof(s)-1);
+ if (bytes_read < 0)
+ {
+ int read_errno = errno;
+ if (log)
+ log->Printf("read (stdout_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
+ }
+ else if (bytes_read == 0)
+ {
+ // EOF...
+ if (log)
+ log->Printf("read (stdout_fd, ) => %d (reached EOF for child STDOUT)", bytes_read);
+ stdout_fd = -1;
+ }
+ else if (bytes_read > 0)
+ {
+ proc->AppendSTDOUT(s, bytes_read);
+ }
+
+ } while (bytes_read > 0);
+ }
+
+ if (stderr_fd >= 0 && FD_ISSET (stderr_fd, &read_fds))
+ {
+ do
+ {
+ bytes_read = ::read (stderr_fd, s, sizeof(s)-1);
+ if (bytes_read < 0)
+ {
+ int read_errno = errno;
+ if (log)
+ log->Printf("read (stderr_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
+ }
+ else if (bytes_read == 0)
+ {
+ // EOF...
+ if (log)
+ log->Printf("read (stderr_fd, ) => %d (reached EOF for child STDERR)", bytes_read);
+ stderr_fd = -1;
+ }
+ else if (bytes_read > 0)
+ {
+ proc->AppendSTDOUT(s, bytes_read);
+ }
+
+ } while (bytes_read > 0);
+ }
+ }
+ }
+
+ if (log)
+ log->Printf("ProcessMacOSX::%s (%p): thread exiting...", __FUNCTION__, arg);
+
+ return NULL;
+}
+
+Error
+ProcessMacOSX::DoSignal (int signal)
+{
+ Error error;
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessMacOSX::DoSignal (signal = %d)", signal);
+ if (::kill (GetID(), signal) != 0)
+ {
+ error.SetErrorToErrno();
+ error.LogIfError(log, "ProcessMacOSX::DoSignal (%d)", signal);
+ }
+ return error;
+}
+
+
+Error
+ProcessMacOSX::DoDetach()
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessMacOSX::DoDetach()");
+
+ Error error (DoSIGSTOP (true));
+ if (error.Success())
+ {
+ CloseChildFileDescriptors ();
+
+ // Scope for "locker" so we can reply to all of our exceptions (the SIGSTOP
+ // exception).
+ {
+ Mutex::Locker locker(m_exception_messages_mutex);
+ ReplyToAllExceptions();
+ }
+
+ // Shut down the exception thread and cleanup our exception remappings
+ Task().ShutDownExceptionThread();
+
+ lldb::pid_t pid = GetID();
+
+ // Detach from our process while we are stopped.
+ errno = 0;
+
+ // Detach from our process
+ ::ptrace (PT_DETACH, pid, (caddr_t)1, 0);
+
+ error.SetErrorToErrno();
+
+ if (log || error.Fail())
+ error.PutToLog(log, "::ptrace (PT_DETACH, %u, (caddr_t)1, 0)", pid);
+
+ // Resume our task
+ Task().Resume();
+
+ // NULL our task out as we have already retored all exception ports
+ Task().Clear();
+
+ // Clear out any notion of the process we once were
+ Clear();
+
+ SetPrivateState (eStateDetached);
+ }
+ return error;
+}
+
+
+
+Error
+ProcessMacOSX::ReplyToAllExceptions()
+{
+ Error error;
+ Mutex::Locker locker(m_exception_messages_mutex);
+ if (m_exception_messages.empty() == false)
+ {
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+
+ MachException::Message::iterator pos;
+ MachException::Message::iterator begin = m_exception_messages.begin();
+ MachException::Message::iterator end = m_exception_messages.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ int resume_signal = -1;
+ ThreadSP thread_sp = m_thread_list.FindThreadByID(pos->state.thread_port);
+ if (thread_sp.get())
+ resume_signal = thread_sp->GetResumeSignal();
+ if (log)
+ log->Printf ("Replying to exception %d for thread 0x%4.4x (resume_signal = %i).", std::distance(begin, pos), thread_sp->GetID(), resume_signal);
+ Error curr_error (pos->Reply (Task().GetTaskPort(), GetID(), resume_signal));
+
+ // Only report the first error
+ if (curr_error.Fail() && error.Success())
+ error = curr_error;
+
+ error.LogIfError(log, "Error replying to exception");
+ }
+
+ // Erase all exception message as we should have used and replied
+ // to them all already.
+ m_exception_messages.clear();
+ }
+ return error;
+}
+
+
+Error
+ProcessMacOSX::PrivateResume (lldb::tid_t tid)
+{
+
+ Mutex::Locker locker(m_exception_messages_mutex);
+ Error error (ReplyToAllExceptions());
+
+ // Let the thread prepare to resume and see if any threads want us to
+ // step over a breakpoint instruction (ProcessWillResume will modify
+ // the value of stepOverBreakInstruction).
+ //StateType process_state = m_thread_list.ProcessWillResume(this);
+
+ // Set our state accordingly
+ SetPrivateState (eStateRunning);
+
+ // Now resume our task.
+ error = Task().Resume();
+ return error;
+}
+
+// Called by the exception thread when an exception has been received from
+// our process. The exception message is completely filled and the exception
+// data has already been copied.
+void
+ProcessMacOSX::ExceptionMessageReceived (const MachException::Message& exceptionMessage)
+{
+ Mutex::Locker locker(m_exception_messages_mutex);
+
+ if (m_exception_messages.empty())
+ Task().Suspend();
+
+ ProcessMacOSXLog::LogIf (PD_LOG_EXCEPTIONS, "ProcessMacOSX::ExceptionMessageReceived ( )");
+
+ // Use a locker to automatically unlock our mutex in case of exceptions
+ // Add the exception to our internal exception stack
+ m_exception_messages.push_back(exceptionMessage);
+}
+
+
+//bool
+//ProcessMacOSX::GetProcessInfo (struct kinfo_proc* proc_info)
+//{
+// int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, GetID() };
+// size_t buf_size = sizeof(struct kinfo_proc);
+//
+// if (::sysctl (mib, (unsigned)(sizeof(mib)/sizeof(int)), &proc_info, &buf_size, NULL, 0) == 0)
+// return buf_size > 0;
+//
+// return false;
+//}
+//
+//
+void
+ProcessMacOSX::ExceptionMessageBundleComplete()
+{
+ // We have a complete bundle of exceptions for our child process.
+ Mutex::Locker locker(m_exception_messages_mutex);
+ ProcessMacOSXLog::LogIf (PD_LOG_EXCEPTIONS, "%s: %d exception messages.", __PRETTY_FUNCTION__, m_exception_messages.size());
+ if (!m_exception_messages.empty())
+ {
+ SetPrivateState (eStateStopped);
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_EXCEPTIONS, "%s empty exception messages bundle.", __PRETTY_FUNCTION__, m_exception_messages.size());
+ }
+}
+
+bool
+ProcessMacOSX::ReleaseChildFileDescriptors ( int *stdin_fileno, int *stdout_fileno, int *stderr_fileno )
+{
+ if (stdin_fileno)
+ *stdin_fileno = m_child_stdin;
+ if (stdout_fileno)
+ *stdout_fileno = m_child_stdout;
+ if (stderr_fileno)
+ *stderr_fileno = m_child_stderr;
+ // Stop the stdio thread if we have one, but don't have it close the child
+ // file descriptors since we are giving control of these descriptors to the
+ // caller
+ bool close_child_fds = false;
+ StopSTDIOThread(close_child_fds);
+ return true;
+}
+
+void
+ProcessMacOSX::AppendSTDOUT (const char* s, size_t len)
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSX::%s (<%d> %s) ...", __FUNCTION__, len, s);
+ Mutex::Locker locker(m_stdio_mutex);
+ m_stdout_data.append(s, len);
+
+ // FIXME: Make a real data object for this and put it out.
+ BroadcastEventIfUnique (eBroadcastBitSTDOUT);
+}
+
+lldb::pid_t
+ProcessMacOSX::LaunchForDebug
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ PDLaunchType launch_type,
+ Error &launch_err)
+{
+ // Clear out and clean up from any current state
+ Clear();
+
+ m_arch_spec = arch_spec;
+
+ if (launch_type == eLaunchDefault)
+ launch_type = eLaunchPosixSpawn;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("%s( path = '%s', argv = %p, envp = %p, launch_type = %u )", __FUNCTION__, path, argv, envp, launch_type);
+
+ // Fork a child process for debugging
+ SetPrivateState (eStateLaunching);
+ switch (launch_type)
+ {
+ case eLaunchForkExec:
+ SetID(ProcessMacOSX::ForkChildForPTraceDebugging(path, argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, this, launch_err));
+ break;
+
+ case eLaunchPosixSpawn:
+ SetID(ProcessMacOSX::PosixSpawnChildForPTraceDebugging(path, argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, this, launch_err));
+ break;
+
+#if defined (__arm__)
+
+ case eLaunchSpringBoard:
+ {
+ const char *app_ext = strstr(path, ".app");
+ if (app_ext != NULL)
+ {
+ std::string app_bundle_path(path, app_ext + strlen(".app"));
+ return SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, launch_err);
+ }
+ }
+ break;
+
+#endif
+
+ default:
+ // Invalid launch
+ launch_err.SetErrorToGenericError ();
+ return LLDB_INVALID_PROCESS_ID;
+ }
+
+ lldb::pid_t pid = GetID();
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // If we don't have a valid process ID and no one has set the error,
+ // then return a generic error
+ if (launch_err.Success())
+ launch_err.SetErrorToGenericError ();
+ }
+ else
+ {
+ // Make sure we can get our task port before going any further
+ Task().GetTaskPortForProcessID (launch_err);
+
+ // If that goes well then kick off our exception thread
+ if (launch_err.Success())
+ Task().StartExceptionThread(launch_err);
+
+ if (launch_err.Success())
+ {
+ //m_path = path;
+// size_t i;
+// if (argv)
+// {
+// char const *arg;
+// for (i=0; (arg = argv[i]) != NULL; i++)
+// m_args.push_back(arg);
+// }
+
+ StartSTDIOThread();
+
+ if (launch_type == eLaunchPosixSpawn)
+ {
+
+ //SetState (eStateAttaching);
+ errno = 0;
+ if (::ptrace (PT_ATTACHEXC, pid, 0, 0) == 0)
+ launch_err.Clear();
+ else
+ launch_err.SetErrorToErrno();
+
+ if (launch_err.Fail() || log)
+ launch_err.PutToLog(log, "::ptrace (PT_ATTACHEXC, pid = %i, 0, 0 )", pid);
+
+ if (launch_err.Success())
+ m_flags.Set (eFlagsAttached);
+ else
+ SetPrivateState (eStateExited);
+ }
+ else
+ {
+ launch_err.Clear();
+ }
+ }
+ else
+ {
+ // We were able to launch the process, but not get its task port
+ // so now we need to make it sleep with da fishes.
+ SetID(LLDB_INVALID_PROCESS_ID);
+ ::ptrace (PT_KILL, pid, 0, 0 );
+ ::kill (pid, SIGCONT);
+ pid = LLDB_INVALID_PROCESS_ID;
+ }
+
+ }
+ return pid;
+}
+
+lldb::pid_t
+ProcessMacOSX::PosixSpawnChildForPTraceDebugging
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSX* process,
+ Error &err
+)
+{
+ posix_spawnattr_t attr;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+
+ Error local_err; // Errors that don't affect the spawning.
+ if (log)
+ log->Printf ("%s ( path='%s', argv=%p, envp=%p, process )", __FUNCTION__, path, argv, envp);
+ err.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX);
+ if (err.Fail() || log)
+ err.PutToLog(log, "::posix_spawnattr_init ( &attr )");
+ if (err.Fail())
+ return LLDB_INVALID_PROCESS_ID;
+
+ err.SetError( ::posix_spawnattr_setflags (&attr, POSIX_SPAWN_START_SUSPENDED), eErrorTypePOSIX);
+ if (err.Fail() || log)
+ err.PutToLog(log, "::posix_spawnattr_setflags ( &attr, POSIX_SPAWN_START_SUSPENDED )");
+ if (err.Fail())
+ return LLDB_INVALID_PROCESS_ID;
+
+#if !defined(__arm__)
+
+ // We don't need to do this for ARM, and we really shouldn't now that we
+ // have multiple CPU subtypes and no posix_spawnattr call that allows us
+ // to set which CPU subtype to launch...
+ cpu_type_t cpu = arch_spec.GetCPUType();
+ if (cpu != 0 && cpu != CPU_TYPE_ANY && cpu != LLDB_INVALID_CPUTYPE)
+ {
+ size_t ocount = 0;
+ err.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX);
+ if (err.Fail() || log)
+ err.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %zu )", cpu, ocount);
+
+ if (err.Fail() != 0 || ocount != 1)
+ return LLDB_INVALID_PROCESS_ID;
+ }
+
+#endif
+
+ lldb_utility::PseudoTerminal pty;
+
+ posix_spawn_file_actions_t file_actions;
+ err.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX);
+ int file_actions_valid = err.Success();
+ if (!file_actions_valid || log)
+ err.PutToLog(log, "::posix_spawn_file_actions_init ( &file_actions )");
+ Error stdio_err;
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ if (file_actions_valid)
+ {
+ // If the user specified any STDIO files, then use those
+ if (stdin_path || stdout_path || stderr_path)
+ {
+ process->SetSTDIOIsOurs(false);
+ if (stderr_path != NULL && stderr_path[0])
+ {
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDERR_FILENO, stderr_path, O_RDWR, 0), eErrorTypePOSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.PutToLog(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDERR_FILENO, path = '%s', oflag = O_RDWR, mode = 0 )", stderr_path);
+ }
+
+ if (stdin_path != NULL && stdin_path[0])
+ {
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDIN_FILENO, stdin_path, O_RDONLY, 0), eErrorTypePOSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.PutToLog(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDIN_FILENO, path = '%s', oflag = O_RDONLY, mode = 0 )", stdin_path);
+ }
+
+ if (stdout_path != NULL && stdout_path[0])
+ {
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDOUT_FILENO, stdout_path, O_WRONLY, 0), eErrorTypePOSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.PutToLog(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDOUT_FILENO, path = '%s', oflag = O_WRONLY, mode = 0 )", stdout_path);
+ }
+ }
+ else
+ {
+ // The user did not specify any STDIO files, use a pseudo terminal.
+ // Callers can then access the file handles using the
+ // ProcessMacOSX::ReleaseChildFileDescriptors() function, otherwise
+ // this class will spawn a thread that tracks STDIO and buffers it.
+ process->SetSTDIOIsOurs(true);
+ char error_str[1024];
+ if (pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, error_str, sizeof(error_str)))
+ {
+ const char* slave_name = pty.GetSlaveName(error_str, sizeof(error_str));
+ if (slave_name == NULL)
+ slave_name = "/dev/null";
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDERR_FILENO, slave_name, O_RDWR|O_NOCTTY, 0), eErrorTypePOSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.PutToLog(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDERR_FILENO, path = '%s', oflag = O_RDWR|O_NOCTTY, mode = 0 )", slave_name);
+
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDIN_FILENO, slave_name, O_RDONLY|O_NOCTTY, 0), eErrorTypePOSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.PutToLog(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDIN_FILENO, path = '%s', oflag = O_RDONLY|O_NOCTTY, mode = 0 )", slave_name);
+
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDOUT_FILENO, slave_name, O_WRONLY|O_NOCTTY, 0), eErrorTypePOSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.PutToLog(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDOUT_FILENO, path = '%s', oflag = O_WRONLY|O_NOCTTY, mode = 0 )", slave_name);
+ }
+ else
+ {
+ if (error_str[0])
+ stdio_err.SetErrorString(error_str);
+ else
+ stdio_err.SetErrorString("Unable to open master side of pty for inferior.");
+ }
+
+ }
+ err.SetError( ::posix_spawnp (&pid, path, &file_actions, &attr, (char * const*)argv, (char * const*)envp), eErrorTypePOSIX);
+ if (err.Fail() || log)
+ err.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, &file_actions, &attr, argv, envp);
+
+ if (stdio_err.Success())
+ {
+ // If we have a valid process and we created the STDIO file handles,
+ // then remember them on our process class so we can spawn a STDIO
+ // thread and close them when we are done with them.
+ if (process != NULL && process->STDIOIsOurs())
+ {
+ int master_fd = pty.ReleaseMasterFileDescriptor ();
+ process->SetChildFileDescriptors (master_fd, master_fd, master_fd);
+ }
+ }
+ }
+ else
+ {
+ err.SetError( ::posix_spawnp (&pid, path, NULL, &attr, (char * const*)argv, (char * const*)envp), eErrorTypePOSIX);
+ if (err.Fail() || log)
+ err.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, NULL, &attr, argv, envp);
+ }
+
+ // We have seen some cases where posix_spawnp was returning a valid
+ // looking pid even when an error was returned, so clear it out
+ if (err.Fail())
+ pid = LLDB_INVALID_PROCESS_ID;
+
+ if (file_actions_valid)
+ {
+ local_err.SetError( ::posix_spawn_file_actions_destroy (&file_actions), eErrorTypePOSIX);
+ if (local_err.Fail() || log)
+ local_err.PutToLog(log, "::posix_spawn_file_actions_destroy ( &file_actions )");
+ }
+
+ return pid;
+}
+
+lldb::pid_t
+ProcessMacOSX::ForkChildForPTraceDebugging
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSX* process,
+ Error &launch_err
+)
+{
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ if (stdin_path || stdout_path || stderr_path)
+ {
+ assert(!"TODO: ForkChildForPTraceDebugging doesn't currently support fork/exec with user file handles...");
+ }
+ else
+ {
+
+ // Use a fork that ties the child process's stdin/out/err to a pseudo
+ // terminal so we can read it in our ProcessMacOSX::STDIOThread
+ // as unbuffered io.
+ lldb_utility::PseudoTerminal pty;
+ char error_str[1024];
+ pid = pty.Fork(error_str, sizeof(error_str));
+
+ if (pid < 0)
+ {
+ launch_err.SetErrorString (error_str);
+ //--------------------------------------------------------------
+ // Error during fork.
+ //--------------------------------------------------------------
+ return pid;
+ }
+ else if (pid == 0)
+ {
+ //--------------------------------------------------------------
+ // Child process
+ //--------------------------------------------------------------
+ ::ptrace (PT_TRACE_ME, 0, 0, 0); // Debug this process
+ ::ptrace (PT_SIGEXC, 0, 0, 0); // Get BSD signals as mach exceptions
+
+ // If our parent is setgid, lets make sure we don't inherit those
+ // extra powers due to nepotism.
+ ::setgid (getgid ());
+
+ // Let the child have its own process group. We need to execute
+ // this call in both the child and parent to avoid a race condition
+ // between the two processes.
+ ::setpgid (0, 0); // Set the child process group to match its pid
+
+ // Sleep a bit to before the exec call
+ ::sleep (1);
+
+ // Turn this process into
+ ::execv (path, (char * const *)argv);
+ // Exit with error code. Child process should have taken
+ // over in above exec call and if the exec fails it will
+ // exit the child process below.
+ ::exit (127);
+ }
+ else
+ {
+ //--------------------------------------------------------------
+ // Parent process
+ //--------------------------------------------------------------
+ // Let the child have its own process group. We need to execute
+ // this call in both the child and parent to avoid a race condition
+ // between the two processes.
+ ::setpgid (pid, pid); // Set the child process group to match its pid
+
+ if (process != NULL)
+ {
+ // Release our master pty file descriptor so the pty class doesn't
+ // close it and so we can continue to use it in our STDIO thread
+ int master_fd = pty.ReleaseMasterFileDescriptor ();
+ process->SetChildFileDescriptors (master_fd, master_fd, master_fd);
+ }
+ }
+ }
+ return pid;
+}
+
+#if defined (__arm__)
+
+lldb::pid_t
+ProcessMacOSX::SBLaunchForDebug
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ Error &launch_err
+)
+{
+ // Clear out and clean up from any current state
+ Clear();
+
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path);
+
+ // Fork a child process for debugging
+ SetState(eStateLaunching);
+ m_pid = ProcessMacOSX::SBLaunchForDebug(path, argv, envp, this, launch_err);
+ if (m_pid != 0)
+ {
+ m_flags |= eFlagsUsingSBS;
+ //m_path = path;
+// size_t i;
+// char const *arg;
+// for (i=0; (arg = argv[i]) != NULL; i++)
+// m_args.push_back(arg);
+ Task().StartExceptionThread();
+ StartSTDIOThread();
+ SetState (eStateAttaching);
+ int err = ptrace (PT_ATTACHEXC, m_pid, 0, 0);
+ if (err == 0)
+ {
+ m_flags |= eFlagsAttached;
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "successfully attached to pid %d", m_pid);
+ }
+ else
+ {
+ SetState (eStateExited);
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "error: failed to attach to pid %d", m_pid);
+ }
+ }
+ return m_pid;
+}
+
+#include <servers/bootstrap.h>
+#include "CFBundle.h"
+#include "CFData.h"
+#include "CFString.h"
+
+lldb::pid_t
+ProcessMacOSX::SBLaunchForDebug
+(
+ const char *app_bundle_path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSX* process,
+ Error &launch_err
+)
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, app_bundle_path, process);
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+ if (argv[0] == NULL)
+ return LLDB_INVALID_PROCESS_ID;
+
+ size_t argc = 0;
+ // Count the number of arguments
+ while (argv[argc] != NULL)
+ argc++;
+
+ // Enumerate the arguments
+ size_t first_launch_arg_idx = 1;
+ CFReleaser<CFMutableArrayRef> launch_argv;
+
+ if (argv[first_launch_arg_idx])
+ {
+ size_t launch_argc = argc > 0 ? argc - 1 : 0;
+ launch_argv.reset (::CFArrayCreateMutable (alloc, launch_argc, &kCFTypeArrayCallBacks));
+ size_t i;
+ char const *arg;
+ CFString launch_arg;
+ for (i=first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); i++)
+ {
+ launch_arg.reset(::CFStringCreateWithCString (alloc, arg, kCFStringEncodingUTF8));
+ if (launch_arg.get() != NULL)
+ CFArrayAppendValue(launch_argv.get(), launch_arg.get());
+ else
+ break;
+ }
+ }
+
+ // Next fill in the arguments dictionary. Note, the envp array is of the form
+ // Variable=value but SpringBoard wants a CF dictionary. So we have to convert
+ // this here.
+
+ CFReleaser<CFMutableDictionaryRef> launch_envp;
+
+ if (envp[0])
+ {
+ launch_envp.reset(::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+ const char *value;
+ int name_len;
+ CFString name_string, value_string;
+
+ for (int i = 0; envp[i] != NULL; i++)
+ {
+ value = strstr (envp[i], "=");
+
+ // If the name field is empty or there's no =, skip it. Somebody's messing with us.
+ if (value == NULL || value == envp[i])
+ continue;
+
+ name_len = value - envp[i];
+
+ // Now move value over the "="
+ value++;
+
+ name_string.reset(::CFStringCreateWithBytes(alloc, (const UInt8 *) envp[i], name_len, kCFStringEncodingUTF8, false));
+ value_string.reset(::CFStringCreateWithCString(alloc, value, kCFStringEncodingUTF8));
+ CFDictionarySetValue (launch_envp.get(), name_string.get(), value_string.get());
+ }
+ }
+
+ CFString stdout_cf_path;
+ CFString stderr_cf_path;
+ PseudoTerminal pty;
+
+ if (stdin_path || stdout_path || stderr_path)
+ {
+ process->SetSTDIOIsOurs(false);
+ if (stdout_path)
+ stdout_cf_path.SetFileSystemRepresentation (stdout_path);
+ if (stderr_path)
+ stderr_cf_path.SetFileSystemRepresentation (stderr_path);
+ }
+ else
+ {
+ process->SetSTDIOIsOurs(true);
+ PseudoTerminal::Error pty_err = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY);
+ if (pty_err == PseudoTerminal::success)
+ {
+ const char* slave_name = pty.SlaveName();
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() successfully opened master pty, slave is %s", __FUNCTION__, slave_name);
+ if (slave_name && slave_name[0])
+ {
+ ::chmod (slave_name, S_IRWXU | S_IRWXG | S_IRWXO);
+ stdout_cf_path.SetFileSystemRepresentation (slave_name);
+ stderr_cf_path.(stdout_cf_path);
+ }
+ }
+ }
+
+ if (stdout_cf_path.get() == NULL)
+ stdout_cf_path.SetFileSystemRepresentation ("/dev/null");
+ if (stderr_cf_path.get() == NULL)
+ stderr_cf_path.SetFileSystemRepresentation ("/dev/null");
+
+ CFBundle bundle(app_bundle_path);
+ CFStringRef bundleIDCFStr = bundle.GetIdentifier();
+ std::string bundleID;
+ if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL)
+ {
+ struct stat app_bundle_stat;
+ if (::stat (app_bundle_path, &app_bundle_stat) < 0)
+ {
+ launch_err.SetError(errno, eErrorTypePOSIX);
+ launch_err.SetErrorStringWithFormat("%s: \"%s\".\n", launch_err.AsString(), app_bundle_path);
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() error: %s", __FUNCTION__, launch_err.AsCString());
+ }
+ else
+ {
+ launch_err.SetError(-1, eErrorTypeGeneric);
+ launch_err.SetErrorStringWithFormat("Failed to extract CFBundleIdentifier from %s.\n", app_bundle_path);
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() error: failed to extract CFBundleIdentifier from '%s'", __FUNCTION__, app_bundle_path);
+ }
+ return LLDB_INVALID_PROCESS_ID;
+ }
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", __FUNCTION__, bundleID.c_str());
+
+
+ CFData argv_data(NULL);
+
+ if (launch_argv.get())
+ {
+ if (argv_data.Serialize(launch_argv.get(), kCFPropertyListBinaryFormat_v1_0) == NULL)
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() error: failed to serialize launch arg array...", __FUNCTION__);
+ return LLDB_INVALID_PROCESS_ID;
+ }
+ }
+
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() serialized launch arg array", __FUNCTION__);
+
+ // Find SpringBoard
+ SBSApplicationLaunchError sbs_error = 0;
+ sbs_error = SBSLaunchApplication ( bundleIDCFStr,
+ (CFURLRef)NULL, // openURL
+ launch_argv.get(),
+ launch_envp.get(), // CFDictionaryRef environment
+ stdout_cf_path.get(),
+ stderr_cf_path.get(),
+ SBSApplicationLaunchWaitForDebugger | SBSApplicationLaunchUnlockDevice);
+
+
+ launch_err.SetError(sbs_error, eErrorTypeSpringBoard);
+
+ if (sbs_error == SBSApplicationLaunchErrorSuccess)
+ {
+ static const useconds_t pid_poll_interval = 200000;
+ static const useconds_t pid_poll_timeout = 30000000;
+
+ useconds_t pid_poll_total = 0;
+
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ Boolean pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
+ // Poll until the process is running, as long as we are getting valid responses and the timeout hasn't expired
+ // A return PID of 0 means the process is not running, which may be because it hasn't been (asynchronously) started
+ // yet, or that it died very quickly (if you weren't using waitForDebugger).
+ while (!pid_found && pid_poll_total < pid_poll_timeout)
+ {
+ usleep (pid_poll_interval);
+ pid_poll_total += pid_poll_interval;
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() polling Springboard for pid for %s...", __FUNCTION__, bundleID.c_str());
+ pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
+ }
+
+ if (pid_found)
+ {
+ // If we have a valid process and we created the STDIO file handles,
+ // then remember them on our process class so we can spawn a STDIO
+ // thread and close them when we are done with them.
+ if (process != NULL && process->STDIOIsOurs())
+ {
+ // Release our master pty file descriptor so the pty class doesn't
+ // close it and so we can continue to use it in our STDIO thread
+ int master_fd = pty.ReleaseMasterFD();
+ process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
+ }
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() => pid = %4.4x", __FUNCTION__, pid);
+ }
+ else
+ {
+ LogError("failed to lookup the process ID for CFBundleIdentifier %s.", bundleID.c_str());
+ }
+ return pid;
+ }
+
+ LogError("unable to launch the application with CFBundleIdentifier '%s' sbs_error = %u", bundleID.c_str(), sbs_error);
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+#endif // #if defined (__arm__)
+
+
+#include "MachThreadContext_x86_64.h"
+#include "MachThreadContext_i386.h"
+#include "MachThreadContext_arm.h"
+
+void
+ProcessMacOSX::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (g_initialized == false)
+ {
+ g_initialized = true;
+
+ MachThreadContext_x86_64::Initialize();
+ MachThreadContext_i386::Initialize();
+ MachThreadContext_arm::Initialize();
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+
+ Log::Callbacks log_callbacks = {
+ ProcessMacOSXLog::DisableLog,
+ ProcessMacOSXLog::EnableLog,
+ ProcessMacOSXLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessMacOSX::GetPluginNameStatic(), log_callbacks);
+
+
+ }
+}
+
+
+
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.h b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.h
new file mode 100644
index 00000000000..8388d4e46fe
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.h
@@ -0,0 +1,490 @@
+//===-- ProcessMacOSX.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MacOSXProcess_H_
+#define liblldb_MacOSXProcess_H_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+// Project includes
+#include "MachTask.h"
+#include "MachException.h"
+
+typedef enum PDLaunch
+{
+ eLaunchDefault = 0,
+ eLaunchPosixSpawn,
+ eLaunchForkExec,
+#if defined (__arm__)
+ eLaunchSpringBoard,
+#endif
+} PDLaunchType;
+
+
+
+class ThreadMacOSX;
+class MachThreadContext;
+
+class ProcessMacOSX :
+ public lldb_private::Process
+{
+public:
+ friend class ThreadMacOSX;
+ friend class MachTask;
+
+ typedef MachThreadContext* (*CreateArchCalback) (const lldb_private::ArchSpec &arch_spec, ThreadMacOSX &thread);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ static Process*
+ CreateInstance (lldb_private::Target& target, lldb_private::Listener &listener);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessMacOSX(lldb_private::Target& target, lldb_private::Listener &listener);
+
+ virtual
+ ~ProcessMacOSX();
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ virtual bool
+ CanDebug (lldb_private::Target &target);
+
+ //------------------------------------------------------------------
+ // 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* module,
+ char const *argv[], // Can be NULL
+ char const *envp[], // Can be NULL
+ const char *stdin_path, // Can be NULL
+ const char *stdout_path, // Can be NULL
+ const char *stderr_path); // Can be NULL
+
+ virtual void
+ DidLaunch ();
+
+ virtual lldb_private::Error
+ WillAttach (lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ DoAttach (lldb::pid_t pid);
+
+ virtual void
+ DidAttach ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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);
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ DoResume ();
+
+ virtual lldb_private::Error
+ DoHalt ();
+
+ virtual lldb_private::Error
+ WillDetach ();
+
+ virtual lldb_private::Error
+ DoDetach ();
+
+ 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
+ DoDeallocateMemory (lldb::addr_t ptr);
+
+ //------------------------------------------------------------------
+ // Process STDIO
+ //------------------------------------------------------------------
+ virtual size_t
+ GetSTDOUT (char *buf, size_t buf_size, lldb_private::Error &error);
+
+ virtual size_t
+ GetSTDERR (char *buf, size_t buf_size, lldb_private::Error &error);
+
+ virtual size_t
+ PutSTDIN (const char *buf, size_t buf_size, lldb_private::Error &error);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode (lldb_private::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableBreakpoint (lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ DisableBreakpoint (lldb_private::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Watchpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableWatchpoint (lldb_private::WatchpointLocation *wp_loc);
+
+ virtual lldb_private::Error
+ DisableWatchpoint (lldb_private::WatchpointLocation *wp_loc);
+
+ virtual lldb::ByteOrder
+ GetByteOrder () const;
+
+ virtual lldb_private::DynamicLoader *
+ GetDynamicLoader ();
+
+ static void
+ AddArchCreateCallback(const lldb_private::ArchSpec& arch_spec,
+ ProcessMacOSX::CreateArchCalback callback);
+
+protected:
+
+ bool m_stdio_ours; // True if we created and own the child STDIO file handles, false if they were supplied to us and owned by someone else
+ int m_child_stdin;
+ int m_child_stdout;
+ int m_child_stderr;
+ MachTask m_task; // The mach task for this process
+ lldb_private::Flags m_flags; // Process specific flags (see eFlags enums)
+ lldb::thread_t m_stdio_thread; // Thread ID for the thread that watches for child process stdio
+ lldb_private::Mutex m_stdio_mutex; // Multithreaded protection for stdio
+ std::string m_stdout_data;
+ MachException::Message::collection m_exception_messages; // A collection of exception messages caught when listening to the exception port
+ lldb_private::Mutex m_exception_messages_mutex; // Multithreaded protection for m_exception_messages
+ lldb_private::ArchSpec m_arch_spec;
+ std::auto_ptr<lldb_private::DynamicLoader> m_dynamic_loader_ap;
+// lldb::thread_t m_wait_thread;
+ lldb::ByteOrder m_byte_order;
+
+ //----------------------------------------------------------------------
+ // Child process control
+ //----------------------------------------------------------------------
+ lldb::pid_t
+ LaunchForDebug (const char *path,
+ char const *argv[],
+ char const *envp[],
+ lldb_private::ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ PDLaunchType launch_type,
+ lldb_private::Error &launch_err);
+
+ static lldb::pid_t
+ ForkChildForPTraceDebugging (const char *path,
+ char const *argv[],
+ char const *envp[],
+ lldb_private::ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSX* process,
+ lldb_private::Error &launch_err);
+
+ static lldb::pid_t
+ PosixSpawnChildForPTraceDebugging (const char *path,
+ char const *argv[],
+ char const *envp[],
+ lldb_private::ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSX* process,
+ lldb_private::Error &launch_err);
+
+#if defined (__arm__)
+ lldb::pid_t
+ SBLaunchForDebug (const char *path,
+ char const *argv[],
+ char const *envp[],
+ lldb_private::ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ lldb_private::Error &launch_err);
+
+ static lldb::pid_t
+ SBLaunchForDebug (const char *path,
+ char const *argv[],
+ char const *envp[],
+ lldb_private::ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSX* process,
+ lldb_private::Error &launch_err);
+#endif
+
+ //----------------------------------------------------------------------
+ // Exception thread functions
+ //----------------------------------------------------------------------
+ bool
+ StartSTDIOThread ();
+
+ void
+ StopSTDIOThread (bool close_child_fds);
+
+ static void *
+ STDIOThread (void *arg);
+
+ void
+ ExceptionMessageReceived (const MachException::Message& exceptionMessage);
+
+ void
+ ExceptionMessageBundleComplete ();
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ bool
+ ProcessIDIsValid ( ) const;
+
+ MachTask&
+ Task() { return m_task; }
+
+ const MachTask&
+ Task() const { return m_task; }
+
+ 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;
+ }
+
+ void
+ SetChildFileDescriptors (int stdin_fileno, int stdout_fileno, int stderr_fileno)
+ {
+ m_child_stdin = stdin_fileno;
+ m_child_stdout = stdout_fileno;
+ m_child_stderr = stderr_fileno;
+ }
+
+ int
+ GetStdinFileDescriptor () const
+ {
+ return m_child_stdin;
+ }
+
+ int
+ GetStdoutFileDescriptor () const
+ {
+ return m_child_stdout;
+ }
+ int
+ GetStderrFileDescriptor () const
+ {
+ return m_child_stderr;
+ }
+ bool
+ ReleaseChildFileDescriptors ( int *stdin_fileno, int *stdout_fileno, int *stderr_fileno );
+
+ void
+ AppendSTDOUT (const char* s, size_t len);
+
+ void
+ CloseChildFileDescriptors ()
+ {
+ if (m_child_stdin >= 0)
+ {
+ ::close (m_child_stdin);
+ m_child_stdin = -1;
+ }
+ if (m_child_stdout >= 0)
+ {
+ ::close (m_child_stdout);
+ m_child_stdout = -1;
+ }
+ if (m_child_stderr >= 0)
+ {
+ ::close (m_child_stderr);
+ m_child_stderr = -1;
+ }
+ }
+
+ bool
+ ProcessUsingSpringBoard() const
+ {
+ return m_flags.IsSet(eFlagsUsingSBS);
+ }
+
+ lldb_private::ArchSpec&
+ GetArchSpec()
+ {
+ return m_arch_spec;
+ }
+ const lldb_private::ArchSpec&
+ GetArchSpec() const
+ {
+ return m_arch_spec;
+ }
+
+ CreateArchCalback
+ GetArchCreateCallback();
+
+ enum
+ {
+ eFlagsNone = 0,
+ eFlagsAttached = (1 << 0),
+ eFlagsUsingSBS = (1 << 1)
+ };
+
+ void
+ Clear ( );
+
+ lldb_private::Error
+ ReplyToAllExceptions();
+
+ lldb_private::Error
+ PrivateResume ( lldb::tid_t tid);
+
+ lldb_private::Flags &
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const lldb_private::Flags &
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ bool
+ STDIOIsOurs() const
+ {
+ return m_stdio_ours;
+ }
+
+ void
+ SetSTDIOIsOurs(bool b)
+ {
+ m_stdio_ours = b;
+ }
+
+ uint32_t
+ UpdateThreadListIfNeeded ();
+
+private:
+
+ void
+ DidLaunchOrAttach ();
+
+ lldb_private::Error
+ DoSIGSTOP (bool clear_all_breakpoints);
+
+ lldb_private::Error
+ WillLaunchOrAttach ();
+
+// static void *
+// WaitForChildProcessToExit (void *pid_ptr);
+//
+//
+ //------------------------------------------------------------------
+ // For ProcessMacOSX only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ProcessMacOSX);
+
+};
+
+#endif // liblldb_MacOSXProcess_H_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.cpp
new file mode 100644
index 00000000000..4bfd1ff466e
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.cpp
@@ -0,0 +1,124 @@
+//===-- ProcessMacOSXLog.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessMacOSXLog.h"
+
+#include "lldb/Core/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessMacOSX.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static Log* g_log = NULL; // Leak for now as auto_ptr was being cleaned up
+ // by global constructors before other threads
+ // were done with it.
+Log *
+ProcessMacOSXLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log = g_log;
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().GetAllFlagBits();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+void
+ProcessMacOSXLog::DisableLog ()
+{
+ if (g_log)
+ {
+ delete g_log;
+ g_log = NULL;
+ }
+}
+
+Log *
+ProcessMacOSXLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, Args &args, Stream *feedback_strm)
+{
+ DisableLog ();
+ g_log = new Log (log_stream_sp);
+ if (g_log)
+ {
+ uint32_t flag_bits = 0;
+ bool got_unknown_category = false;
+ const size_t argc = args.GetArgumentCount();
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *arg = args.GetArgumentAtIndex(i);
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits |= PD_LOG_ALL;
+ else if (::strcasestr (arg, "break") == arg ) flag_bits |= PD_LOG_BREAKPOINTS;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= PD_LOG_DEFAULT;
+ else if (::strcasestr (arg, "exc") == arg ) flag_bits |= PD_LOG_EXCEPTIONS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits |= PD_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= PD_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits |= PD_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "protections")== 0 ) flag_bits |= PD_LOG_MEMORY_PROTECTIONS;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits |= PD_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits |= PD_LOG_STEP;
+ else if (::strcasecmp (arg, "task") == 0 ) flag_bits |= PD_LOG_TASK;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits |= PD_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits |= PD_LOG_VERBOSE;
+ else if (::strcasestr (arg, "watch") == arg ) flag_bits |= PD_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 = PD_LOG_DEFAULT;
+ g_log->GetMask().SetAllFlagBits(flag_bits);
+ g_log->GetOptions().SetAllFlagBits(log_options);
+ }
+ return g_log;
+}
+
+void
+ProcessMacOSXLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf("Logging categories for '%s':\n"
+ "\tall - turn on all available logging categories\n"
+ "\tbreak - log breakpoints\n"
+ "\tdefault - enable the default set of logging categories for liblldb\n"
+ "\tmemory - log memory reads and writes\n"
+ "\tdata-short - log memory bytes for memory reads and writes for short transactions only\n"
+ "\tdata-long - log memory bytes for memory reads and writes for all transactions\n"
+ "\tprocess - log process events and activities\n"
+ "\tprotections - log memory protections\n"
+ "\ttask - log mach task calls\n"
+ "\tthread - log thread events and activities\n"
+ "\tstep - log step related activities\n"
+ "\tverbose - enable verbose loggging\n"
+ "\twatch - log watchpoint related activities\n", ProcessMacOSX::GetPluginNameStatic());
+}
+
+
+void
+ProcessMacOSXLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (mask);
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.h b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.h
new file mode 100644
index 00000000000..cb2a4e8ee98
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXLog.h
@@ -0,0 +1,62 @@
+//===-- ProcessMacOSXLog.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessMacOSXLog_h_
+#define liblldb_ProcessMacOSXLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define PD_LOG_VERBOSE (1u << 0)
+#define PD_LOG_PROCESS (1u << 1)
+#define PD_LOG_THREAD (1u << 2)
+#define PD_LOG_EXCEPTIONS (1u << 3)
+#define PD_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
+#define PD_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
+#define PD_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
+#define PD_LOG_MEMORY_PROTECTIONS (1u << 7) // Log memory protection changes
+#define PD_LOG_BREAKPOINTS (1u << 8)
+#define PD_LOG_WATCHPOINTS (1u << 9)
+#define PD_LOG_STEP (1u << 10)
+#define PD_LOG_TASK (1u << 11)
+#define PD_LOG_ALL (UINT32_MAX)
+#define PD_LOG_DEFAULT (PD_LOG_PROCESS |\
+ PD_LOG_TASK |\
+ PD_LOG_THREAD |\
+ PD_LOG_EXCEPTIONS |\
+ PD_LOG_MEMORY |\
+ PD_LOG_MEMORY_DATA_SHORT |\
+ PD_LOG_BREAKPOINTS |\
+ PD_LOG_WATCHPOINTS |\
+ PD_LOG_STEP )
+
+class ProcessMacOSXLog
+{
+public:
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static void
+ DisableLog ();
+
+ static lldb_private::Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, lldb_private::Args &args, lldb_private::Stream *feedback_strm);
+
+ static void
+ ListLogCategories (lldb_private::Stream *strm);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // liblldb_ProcessMacOSXLog_h_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.cpp
new file mode 100644
index 00000000000..835d003a9b2
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.cpp
@@ -0,0 +1,1819 @@
+//===-- ProcessMacOSXRemote.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// ProcessMacOSXRemote.cpp
+// liblldb
+//
+// Created by Greg Clayton on 4/21/09.
+//
+//
+//----------------------------------------------------------------------
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+//#include <algorithm>
+//#include <map>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "ProcessMacOSXRemote.h"
+#include "ProcessMacOSXLog.h"
+#include "ThreadMacOSX.h"
+
+Process*
+ProcessMacOSXRemote::CreateInstance (Target &target)
+{
+ return new ProcessMacOSXRemote (target);
+}
+
+bool
+ProcessMacOSXRemote::CanDebug(Target &target)
+{
+ // 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();
+ return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessMacOSXRemote constructor
+//----------------------------------------------------------------------
+ProcessMacOSXRemote::ProcessMacOSXRemote(Target& target) :
+ Process (target),
+ m_flags (0),
+ m_arch_spec (),
+ m_dynamic_loader_ap (),
+ m_byte_order(eByteOrderInvalid)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessMacOSXRemote::~DCProcessMacOSXRemote()
+{
+ Clear();
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+lldb::pid_t
+ProcessMacOSXRemote::DoLaunch
+(
+ Module* module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path
+)
+{
+// ::LogSetBitMask (PD_LOG_DEFAULT);
+// ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
+// ::LogSetLogFile ("/dev/stdout");
+
+ ObjectFile * object_file = module->GetObjectFile();
+ if (object_file)
+ {
+ char exec_file_path[PATH_MAX];
+ FileSpec* file_spec_ptr = object_file->GetFileSpec();
+ if (file_spec_ptr)
+ file_spec_ptr->GetPath(exec_file_path, sizeof(exec_file_path));
+
+ ArchSpec arch_spec(module->GetArchitecture());
+
+ switch (arch_spec.GetCPUType())
+ {
+
+ }
+ // Set our user ID to our process ID.
+ SetID(LaunchForDebug(exec_file_path, argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, eLaunchDefault, GetError()));
+ }
+ else
+ {
+ // Set our user ID to an invalid process ID.
+ SetID(LLDB_INVALID_PROCESS_ID);
+ GetError().SetErrorToGenericError ();
+ GetError().SetErrorStringWithFormat ("Failed to get object file from '%s' for arch %s.\n", module->GetFileSpec().GetFilename().AsCString(), module->GetArchitecture().AsCString());
+ }
+
+ // Return the process ID we have
+ return GetID();
+}
+
+lldb::pid_t
+ProcessMacOSXRemote::DoAttach (lldb::pid_t attach_pid)
+{
+ // Set our user ID to the attached process ID (which can be invalid if
+ // the attach fails
+ lldb::pid_t pid = AttachForDebug(attach_pid);
+ SetID(pid);
+
+// if (pid != LLDB_INVALID_PROCESS_ID)
+// {
+// // Wait for a process stopped event, but don't consume it
+// if (WaitForEvents(LLDB_EVENT_STOPPED, NULL, 30))
+// {
+// }
+// }
+//
+ // Return the process ID we have
+ return pid;
+}
+
+
+void
+ProcessMacOSXRemote::DidLaunch ()
+{
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ m_dynamic_loader_ap.reset();
+ }
+ else
+ {
+ Module * exe_module = GetTarget().GetExecutableModule ().get();
+ assert(exe_module);
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ assert(exe_objfile);
+ m_byte_order = exe_objfile->GetByteOrder();
+ assert(m_byte_order != eByteOrderInvalid);
+ // Install a signal handler so we can catch when our child process
+ // dies and set the exit status correctly.
+ m_wait_thread = Host::ThreadCreate (ProcessMacOSXRemote::WaitForChildProcessToExit, &m_uid, &m_error);
+ if (m_wait_thread != LLDB_INVALID_HOST_THREAD)
+ {
+ // Don't need to get the return value of this thread, so just let
+ // it clean up after itself when it dies.
+ Host::ThreadDetach (m_wait_thread, NULL);
+ }
+ m_dynamic_loader_ap.reset(DynamicLoader::FindPlugin(this, "macosx-dyld"));
+ }
+
+}
+
+void
+ProcessMacOSXRemote::DidAttach ()
+{
+ DidLaunch ();
+ m_need_to_run_did_attach = true;
+}
+
+bool
+ProcessMacOSXRemote::DoResume ()
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSXRemote::Resume()");
+ State state = GetState();
+
+ if (CanResume(state))
+ {
+ PrivateResume(LLDB_INVALID_THREAD_ID);
+ }
+ else if (state == eStateRunning)
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "Resume() - task 0x%x is running, ignoring...", m_task.TaskPort());
+ GetError().Clear();
+
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "Resume() - task 0x%x can't continue, ignoring...", m_task.TaskPort());
+ GetError().SetError(UINT_MAX, Error::Generic);
+ }
+
+ return GetError().Success();
+}
+
+size_t
+ProcessMacOSXRemote::GetSoftwareBreakpointTrapOpcode (BreakpointSite *bp_site)
+{
+ ModuleSP exe_module_sp(GetTarget().GetExecutableModule());
+ if (exe_module_sp.get())
+ {
+ const ArchSpec &exe_arch = exe_module_sp->GetArchitecture();
+ const uint8_t *trap_opcode = NULL;
+ uint32_t trap_opcode_size = 0;
+
+ static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 };
+ //static const uint8_t g_thumb_breakpooint_opcode[] = { 0xFE, 0xDE };
+ static const uint8_t g_ppc_breakpoint_opcode[] = { 0x7F, 0xC0, 0x00, 0x08 };
+ static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC };
+
+ switch (exe_arch.GetCPUType())
+ {
+ case CPU_TYPE_ARM:
+ // TODO: fill this in for ARM. We need to dig up the symbol for
+ // the address in the breakpoint locaiton and figure out if it is
+ // an ARM or Thumb breakpoint.
+ trap_opcode = g_arm_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
+ break;
+
+ case CPU_TYPE_POWERPC:
+ case CPU_TYPE_POWERPC64:
+ trap_opcode = g_ppc_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_ppc_breakpoint_opcode);
+ break;
+
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ trap_opcode = g_i386_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_i386_breakpoint_opcode);
+ break;
+
+ default:
+ assert(!"Unhandled architecture in ProcessMacOSXRemote::GetSoftwareBreakpointTrapOpcode()");
+ return 0;
+ }
+
+ if (trap_opcode && trap_opcode_size)
+ {
+ if (bp_loc->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+ }
+ }
+ // No executable yet, so we can't tell what the breakpoint opcode will be.
+ return 0;
+}
+uint32_t
+ProcessMacOSXRemote::UpdateThreadListIfNeeded ()
+{
+ // locker will keep a mutex locked until it goes out of scope
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ProcessMacOSXRemote::%s (pid = %4.4x)", __FUNCTION__, GetID());
+
+ const uint32_t stop_id = GetStopID();
+ if (m_thread_list.GetSize() == 0 || stop_id != m_thread_list.GetID())
+ {
+ m_thread_list.SetID (stop_id);
+ thread_array_t thread_list = NULL;
+ mach_msg_type_number_t thread_list_count = 0;
+ task_t task = Task().TaskPort();
+ Error err(::task_threads (task, &thread_list, &thread_list_count), Error::MachKernel);
+
+ if (log || err.Fail())
+ err.Log(log, "::task_threads ( task = 0x%4.4x, thread_list => %p, thread_list_count => %u )", task, thread_list, thread_list_count);
+
+ if (err.GetError() == KERN_SUCCESS && thread_list_count > 0)
+ {
+ ThreadList curr_thread_list;
+
+ size_t idx;
+ // Iterator through the current thread list and see which threads
+ // we already have in our list (keep them), which ones we don't
+ // (add them), and which ones are not around anymore (remove them).
+ for (idx = 0; idx < thread_list_count; ++idx)
+ {
+ const lldb::tid_t tid = thread_list[idx];
+ ThreadSP thread_sp(m_thread_list.FindThreadByID (tid));
+ if (thread_sp.get() == NULL)
+ thread_sp.reset (new ThreadMacOSX (this, tid));
+ curr_thread_list.AddThread(thread_sp);
+ }
+
+ m_thread_list = curr_thread_list;
+
+ // Free the vm memory given to us by ::task_threads()
+ vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (lldb::tid_t));
+ ::vm_deallocate (::mach_task_self(),
+ (vm_address_t)thread_list,
+ thread_list_size);
+ }
+ }
+ return m_thread_list.GetSize();
+}
+
+bool
+ProcessMacOSXRemote::ShouldStop ()
+{
+ // If we are attaching, let our dynamic loader plug-in know so it can get
+ // an initial list of shared libraries.
+ if (m_need_to_run_did_attach && m_dynamic_loader_ap.get())
+ {
+ m_need_to_run_did_attach = false;
+ m_dynamic_loader_ap->DidAttach();
+ }
+
+ // We must be attaching if we don't already have a valid architecture
+ if (!m_arch_spec.IsValid())
+ {
+ Module *exe_module = GetTarget().GetExecutableModule().get();
+ if (exe_module)
+ m_arch_spec = exe_module->GetArchitecture();
+ }
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ UpdateThreadListIfNeeded ();
+
+ if (m_thread_list.ShouldStop())
+ {
+ // Let each thread know of any exceptions
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+ task_t task = m_task.TaskPort();
+ size_t i;
+ for (i=0; i<m_exception_messages.size(); ++i)
+ {
+ // Let the thread list figure use the ProcessMacOSXRemote to forward all exceptions
+ // on down to each thread.
+ if (m_exception_messages[i].state.task_port == task)
+ {
+ ThreadSP thread_sp(m_thread_list.FindThreadByID(m_exception_messages[i].state.thread_port));
+ if (thread_sp.get())
+ {
+ ThreadMacOSX *macosx_thread = (ThreadMacOSX *)thread_sp.get();
+ macosx_thread->NotifyException (m_exception_messages[i].state);
+ }
+ }
+ if (log)
+ m_exception_messages[i].Log(log);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool
+ProcessMacOSXRemote::DoHalt ()
+{
+ return Kill (SIGINT);
+}
+
+bool
+ProcessMacOSXRemote::WillDetach ()
+{
+ State state = GetState();
+
+ if (IsRunning(state))
+ {
+ m_error.SetErrorToGenericError();
+ m_error.SetErrorString("Process must be stopped in order to detach.");
+ return false;
+ }
+ return true;
+}
+
+bool
+ProcessMacOSXRemote::DoDetach ()
+{
+ m_use_public_queue = false;
+ bool success = Detach();
+ m_use_public_queue = true;
+ if (success)
+ SetState (eStateDetached);
+ return success;
+}
+
+bool
+ProcessMacOSXRemote::DoKill (int signal)
+{
+ return Kill (signal);
+}
+
+
+//------------------------------------------------------------------
+// Thread Queries
+//------------------------------------------------------------------
+
+Thread *
+ProcessMacOSXRemote::GetCurrentThread ()
+{
+ return m_thread_list.GetCurrentThread().get();
+}
+
+ByteOrder
+ProcessMacOSXRemote::GetByteOrder () const
+{
+ return m_byte_order;
+}
+
+
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessMacOSXRemote::IsAlive ()
+{
+ return MachTask::IsValid (Task().TaskPort());
+}
+
+bool
+ProcessMacOSXRemote::IsRunning ()
+{
+ return LLDB_STATE_IS_RUNNING(GetState());
+}
+
+lldb::addr_t
+ProcessMacOSXRemote::GetImageInfoAddress()
+{
+ return Task().GetDYLDAllImageInfosAddress();
+}
+
+DynamicLoader *
+ProcessMacOSXRemote::GetDynamicLoader()
+{
+ return m_dynamic_loader_ap.get();
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+
+size_t
+ProcessMacOSXRemote::DoReadMemory (lldb::addr_t addr, void *buf, size_t size)
+{
+ return Task().ReadMemory(addr, buf, size);
+}
+
+size_t
+ProcessMacOSXRemote::DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size)
+{
+ return Task().WriteMemory(addr, buf, size);
+}
+
+//------------------------------------------------------------------
+// Process STDIO
+//------------------------------------------------------------------
+
+size_t
+ProcessMacOSXRemote::GetSTDOUT (char *buf, size_t buf_size)
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSXRemote::%s (&%p[%u]) ...", __FUNCTION__, buf, buf_size);
+ Mutex::Locker locker(m_stdio_mutex);
+ size_t bytes_available = m_stdout_data.size();
+ if (bytes_available > 0)
+ {
+ if (bytes_available > buf_size)
+ {
+ memcpy(buf, m_stdout_data.data(), buf_size);
+ m_stdout_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ }
+ else
+ {
+ memcpy(buf, m_stdout_data.data(), bytes_available);
+ m_stdout_data.clear();
+ }
+ }
+ return bytes_available;
+}
+
+size_t
+ProcessMacOSXRemote::GetSTDERR (char *buf, size_t buf_size)
+{
+ return 0;
+}
+
+bool
+ProcessMacOSXRemote::EnableBreakpoint (BreakpointLocation *bp)
+{
+ assert (bp != NULL);
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_BREAKPOINTS);
+ lldb::user_id_t breakID = bp->GetID();
+ lldb::addr_t addr = bp->GetAddress();
+ if (bp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessMacOSXRemote::EnableBreakpoint ( breakID = %d ) breakpoint already enabled.", breakID);
+ return true;
+ }
+ else
+ {
+ if (bp->HardwarePreferred())
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(bp->GetThreadID()).get();
+ if (thread)
+ {
+ bp->SetHardwareIndex (thread->EnableHardwareBreakpoint(bp));
+ if (bp->IsHardware())
+ {
+ bp->SetEnabled(true);
+ return true;
+ }
+ }
+ }
+
+ const size_t break_op_size = GetSoftwareBreakpointTrapOpcode (bp);
+ assert (break_op_size > 0);
+ const uint8_t * const break_op = bp->GetTrapOpcodeBytes();
+
+ if (break_op_size > 0)
+ {
+ // Save the original opcode by reading it
+ if (m_task.ReadMemory(addr, bp->GetSavedOpcodeBytes(), break_op_size) == break_op_size)
+ {
+ // Write a software breakpoint in place of the original opcode
+ if (m_task.WriteMemory(addr, break_op, break_op_size) == break_op_size)
+ {
+ uint8_t verify_break_op[4];
+ if (m_task.ReadMemory(addr, verify_break_op, break_op_size) == break_op_size)
+ {
+ if (memcmp(break_op, verify_break_op, break_op_size) == 0)
+ {
+ bp->SetEnabled(true);
+ if (log)
+ log->Printf("ProcessMacOSXRemote::EnableBreakpoint ( breakID = %d ) SUCCESS.", breakID, (uint64_t)addr);
+ return true;
+ }
+ else
+ {
+ GetError().SetErrorString("Failed to verify the breakpoint trap in memory.");
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Unable to read memory to verify breakpoint trap.");
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Unable to write breakpoint trap to memory.");
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Unable to read memory at breakpoint address.");
+ }
+ }
+ }
+
+ if (log)
+ {
+ const char *err_string = GetError().AsCString();
+ log->Printf ("ProcessMacOSXRemote::EnableBreakpoint ( breakID = %d ) error: %s",
+ breakID, err_string ? err_string : "NULL");
+ }
+ GetError().SetErrorToGenericError();
+ return false;
+}
+
+bool
+ProcessMacOSXRemote::DisableBreakpoint (BreakpointLocation *bp)
+{
+ assert (bp != NULL);
+ lldb::addr_t addr = bp->GetAddress();
+ lldb::user_id_t breakID = bp->GetID();
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_BREAKPOINTS);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::DisableBreakpoint (breakID = %d) addr = 0x%8.8llx", breakID, (uint64_t)addr);
+
+ if (bp->IsHardware())
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(bp->GetThreadID()).get();
+ if (thread)
+ {
+ if (thread->DisableHardwareBreakpoint(bp))
+ {
+ bp->SetEnabled(false);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::DisableBreakpoint (breakID = %d) (hardware) => success", breakID);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ const size_t break_op_size = bp->GetByteSize();
+ assert (break_op_size > 0);
+ const uint8_t * const break_op = bp->GetTrapOpcodeBytes();
+ if (break_op_size > 0)
+ {
+ // Clear a software breakoint instruction
+ uint8_t curr_break_op[break_op_size];
+ bool break_op_found = false;
+
+ // Read the breakpoint opcode
+ if (m_task.ReadMemory(addr, curr_break_op, break_op_size) == break_op_size)
+ {
+ bool verify = false;
+ if (bp->IsEnabled())
+ {
+ // 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 (m_task.WriteMemory(addr, bp->GetSavedOpcodeBytes(), break_op_size) == break_op_size)
+ {
+ verify = true;
+ }
+ else
+ {
+ GetError().SetErrorString("Memory write failed when restoring original opcode.");
+ }
+ }
+ else
+ {
+ GetError().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;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::DisableBreakpoint (breakID = %d) is already disabled", breakID);
+ // Set verify to true and so we can check if the original opcode is there
+ verify = true;
+ }
+
+ if (verify)
+ {
+ uint8_t verify_opcode[break_op_size];
+ // Verify that our original opcode made it back to the inferior
+ if (m_task.ReadMemory(addr, verify_opcode, break_op_size) == break_op_size)
+ {
+ // compare the memory we just read with the original opcode
+ if (memcmp(bp->GetSavedOpcodeBytes(), verify_opcode, break_op_size) == 0)
+ {
+ // SUCCESS
+ bp->SetEnabled(false);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::DisableBreakpoint (breakID = %d) SUCCESS", breakID);
+ return true;
+ }
+ else
+ {
+ if (break_op_found)
+ GetError().SetErrorString("Failed to restore original opcode.");
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Failed to read memory to verify that breakpoint trap was restored.");
+ }
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Unable to read memory that should contain the breakpoint trap.");
+ }
+ }
+
+ GetError().SetErrorToGenericError();
+ return false;
+}
+
+bool
+ProcessMacOSXRemote::EnableWatchpoint (WatchpointLocation *wp)
+{
+ if (wp)
+ {
+ lldb::user_id_t watchID = wp->GetID();
+ lldb::addr_t addr = wp->GetAddress();
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_WATCHPOINTS);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::EnableWatchpoint(watchID = %d)", watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessMacOSXRemote::EnableWatchpoint(watchID = %d) addr = 0x%8.8llx: watchpoint already enabled.", watchID, (uint64_t)addr);
+ return true;
+ }
+ else
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(wp->GetThreadID()).get();
+ if (thread)
+ {
+ wp->SetHardwareIndex (thread->EnableHardwareWatchpoint (wp));
+ if (wp->IsHardware ())
+ {
+ wp->SetEnabled(true);
+ return true;
+ }
+ }
+ else
+ {
+ GetError().SetErrorString("Watchpoints currently only support thread specific watchpoints.");
+ }
+ }
+ }
+ return false;
+}
+
+bool
+ProcessMacOSXRemote::DisableWatchpoint (WatchpointLocation *wp)
+{
+ if (wp)
+ {
+ lldb::user_id_t watchID = wp->GetID();
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_WATCHPOINTS);
+
+ lldb::addr_t addr = wp->GetAddress();
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::DisableWatchpoint (watchID = %d) addr = 0x%8.8llx", watchID, (uint64_t)addr);
+
+ if (wp->IsHardware())
+ {
+ ThreadMacOSX *thread = (ThreadMacOSX *)m_thread_list.FindThreadByID(wp->GetThreadID()).get();
+ if (thread)
+ {
+ if (thread->DisableHardwareWatchpoint (wp))
+ {
+ wp->SetEnabled(false);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::Disablewatchpoint (watchID = %d) addr = 0x%8.8llx (hardware) => success", watchID, (uint64_t)addr);
+ return true;
+ }
+ }
+ }
+ // TODO: clear software watchpoints if we implement them
+ }
+ else
+ {
+ GetError().SetErrorString("Watchpoint location argument was NULL.");
+ }
+ GetError().SetErrorToGenericError();
+ return false;
+}
+
+
+static ProcessMacOSXRemote::CreateArchCalback
+ArchDCScriptInterpreter::TypeMap(const ArchSpec& arch_spec, ProcessMacOSXRemote::CreateArchCalback callback, bool add )
+{
+ // We must wrap the "g_arch_map" file static in a function to avoid
+ // any global constructors so we don't get a build verification error
+ typedef std::multimap<ArchSpec, ProcessMacOSXRemote::CreateArchCalback> ArchToProtocolMap;
+ static ArchToProtocolMap g_arch_map;
+
+ if (add)
+ {
+ g_arch_map.insert(std::make_pair(arch_spec, callback));
+ return callback;
+ }
+ else
+ {
+ ArchToProtocolMap::const_iterator pos = g_arch_map.find(arch_spec);
+ if (pos != g_arch_map.end())
+ {
+ return pos->second;
+ }
+ }
+ return NULL;
+}
+
+void
+ProcessMacOSXRemote::AddArchCreateDCScriptInterpreter::Type(const ArchSpec& arch_spec, CreateArchCalback callback)
+{
+ ArchDCScriptInterpreter::TypeMap (arch_spec, callback, true);
+}
+
+ProcessMacOSXRemote::CreateArchCalback
+ProcessMacOSXRemote::GetArchCreateDCScriptInterpreter::Type()
+{
+ return ArchDCScriptInterpreter::TypeMap (m_arch_spec, NULL, false);
+}
+
+void
+ProcessMacOSXRemote::Clear()
+{
+ // Clear any cached thread list while the pid and task are still valid
+
+ m_task.Clear();
+ // Now clear out all member variables
+ CloseChildFileDescriptors();
+
+ m_flags = eFlagsNone;
+ m_thread_list.Clear();
+ {
+ Mutex::Locker locker(m_exception_messages_mutex);
+ m_exception_messages.clear();
+ }
+
+}
+
+
+bool
+ProcessMacOSXRemote::Kill (int signal)
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::Kill(signal = %d)", signal);
+ State state = GetState();
+
+ if (IsRunning(state))
+ {
+ if (::kill (GetID(), signal) == 0)
+ {
+ GetError().Clear();
+ }
+ else
+ {
+ GetError().SetErrorToErrno();
+ GetError().LogIfError(log, "ProcessMacOSXRemote::Kill(%d)", signal);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::Kill(signal = %d) pid %u (task = 0x%4.4x) was't running, ignoring...", signal, GetID(), m_task.TaskPort());
+ GetError().Clear();
+ }
+ return GetError().Success();
+
+}
+
+
+bool
+ProcessMacOSXRemote::Detach()
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSXRemote::Detach()");
+
+ State state = GetState();
+
+ if (!IsRunning(state))
+ {
+ // Resume our process
+ PrivateResume(LLDB_INVALID_THREAD_ID);
+
+ // We have resumed and now we wait for that event to get posted
+ Event event;
+ if (WaitForPrivateEvents(LLDB_EVENT_RUNNING, &event, 2) == false)
+ return false;
+
+
+ // We need to be stopped in order to be able to detach, so we need
+ // to send ourselves a SIGSTOP
+ if (Kill(SIGSTOP))
+ {
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_PROCESS);
+
+ lldb::pid_t pid = GetID();
+ // Wait for our process stop event to get posted
+ if (WaitForPrivateEvents(LLDB_EVENT_STOPPED, &event, 2) == false)
+ {
+ GetError().Log(log, "::kill (pid = %u, SIGSTOP)", pid);
+ return false;
+ }
+
+ // Shut down the exception thread and cleanup our exception remappings
+ m_task.ShutDownExceptionThread();
+
+ // Detach from our process while we are stopped.
+ errno = 0;
+
+ // Detach from our process
+ ::ptrace (PT_DETACH, pid, (caddr_t)1, 0);
+
+ GetError().SetErrorToErrno();
+
+ if (log || GetError().Fail())
+ GetError().Log(log, "::ptrace (PT_DETACH, %u, (caddr_t)1, 0)", pid);
+
+ // Resume our task
+ m_task.Resume();
+
+ // NULL our task out as we have already retored all exception ports
+ m_task.Clear();
+
+ // Clear out any notion of the process we once were
+ Clear();
+ }
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSXRemote::Detach() error: process must be stopped (SIGINT the process first).");
+ }
+ return false;
+}
+
+
+
+void
+ProcessMacOSXRemote::ReplyToAllExceptions()
+{
+ Mutex::Locker locker(m_exception_messages_mutex);
+ if (m_exception_messages.empty() == false)
+ {
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
+
+ MachException::Message::iterator pos;
+ MachException::Message::iterator begin = m_exception_messages.begin();
+ MachException::Message::iterator end = m_exception_messages.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (log)
+ log->Printf ("Replying to exception %d...", std::distance(begin, pos));
+ int resume_signal = 0;
+ ThreadSP thread_sp = m_thread_list.FindThreadByID(pos->state.thread_port);
+ if (thread_sp.get())
+ resume_signal = thread_sp->GetResumeSignal();
+ GetError() = pos->Reply (Task().TaskPort(), GetID(), resume_signal);
+ GetError().LogIfError(log, "Error replying to exception");
+ }
+
+ // Erase all exception message as we should have used and replied
+ // to them all already.
+ m_exception_messages.clear();
+ }
+}
+void
+ProcessMacOSXRemote::PrivateResume (lldb::tid_t tid)
+{
+ Mutex::Locker locker(m_exception_messages_mutex);
+ ReplyToAllExceptions();
+
+ // Let the thread prepare to resume and see if any threads want us to
+ // step over a breakpoint instruction (ProcessWillResume will modify
+ // the value of stepOverBreakInstruction).
+ //StateType process_state = m_thread_list.ProcessWillResume(this);
+
+ // Set our state accordingly
+ SetState(eStateRunning);
+
+ // Now resume our task.
+ GetError() = m_task.Resume();
+
+}
+
+// Called by the exception thread when an exception has been received from
+// our process. The exception message is completely filled and the exception
+// data has already been copied.
+void
+ProcessMacOSXRemote::ExceptionMessageReceived (const MachException::Message& exceptionMessage)
+{
+ Mutex::Locker locker(m_exception_messages_mutex);
+
+ if (m_exception_messages.empty())
+ m_task.Suspend();
+
+ ProcessMacOSXLog::LogIf (PD_LOG_EXCEPTIONS, "ProcessMacOSXRemote::ExceptionMessageReceived ( )");
+
+ // Use a locker to automatically unlock our mutex in case of exceptions
+ // Add the exception to our internal exception stack
+ m_exception_messages.push_back(exceptionMessage);
+}
+
+
+//bool
+//ProcessMacOSXRemote::GetProcessInfo (struct kinfo_proc* proc_info)
+//{
+// int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, GetID() };
+// size_t buf_size = sizeof(struct kinfo_proc);
+//
+// if (::sysctl (mib, (unsigned)(sizeof(mib)/sizeof(int)), &proc_info, &buf_size, NULL, 0) == 0)
+// return buf_size > 0;
+//
+// return false;
+//}
+//
+//
+void
+ProcessMacOSXRemote::ExceptionMessageBundleComplete()
+{
+ // We have a complete bundle of exceptions for our child process.
+ Mutex::Locker locker(m_exception_messages_mutex);
+ ProcessMacOSXLog::LogIf (PD_LOG_EXCEPTIONS, "%s: %d exception messages.", __PRETTY_FUNCTION__, m_exception_messages.size());
+ if (!m_exception_messages.empty())
+ {
+ SetState (eStateStopped);
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_EXCEPTIONS, "%s empty exception messages bundle.", __PRETTY_FUNCTION__, m_exception_messages.size());
+ }
+}
+
+bool
+ProcessMacOSXRemote::ReleaseChildFileDescriptors ( int *stdin_fileno, int *stdout_fileno, int *stderr_fileno )
+{
+ if (stdin_fileno)
+ *stdin_fileno = m_child_stdin;
+ if (stdout_fileno)
+ *stdout_fileno = m_child_stdout;
+ if (stderr_fileno)
+ *stderr_fileno = m_child_stderr;
+ // Stop the stdio thread if we have one, but don't have it close the child
+ // file descriptors since we are giving control of these descriptors to the
+ // caller
+ bool close_child_fds = false;
+ StopSTDIOThread(close_child_fds);
+ return true;
+}
+
+void
+ProcessMacOSXRemote::AppendSTDOUT (char* s, size_t len)
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "ProcessMacOSXRemote::%s (<%d> %s) ...", __FUNCTION__, len, s);
+ Mutex::Locker locker(m_stdio_mutex);
+ m_stdout_data.append(s, len);
+ AppendEvent (LLDB_EVENT_STDIO);
+}
+
+void *
+ProcessMacOSXRemote::STDIOThread(void *arg)
+{
+ ProcessMacOSXRemote *proc = (ProcessMacOSXRemote*) arg;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessMacOSXRemote::%s (arg = %p) thread starting...", __FUNCTION__, arg);
+
+ // We start use a base and more options so we can control if we
+ // are currently using a timeout on the mach_msg. We do this to get a
+ // bunch of related exceptions on our exception port so we can process
+ // then together. When we have multiple threads, we can get an exception
+ // per thread and they will come in consecutively. The main thread loop
+ // will start by calling mach_msg to without having the MACH_RCV_TIMEOUT
+ // flag set in the options, so we will wait forever for an exception on
+ // our exception port. After we get one exception, we then will use the
+ // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current
+ // exceptions for our process. After we have received the last pending
+ // exception, we will get a timeout which enables us to then notify
+ // our main thread that we have an exception bundle avaiable. We then wait
+ // for the main thread to tell this exception thread to start trying to get
+ // exceptions messages again and we start again with a mach_msg read with
+ // infinite timeout.
+ Error err;
+ int stdout_fd = proc->GetStdoutFileDescriptor();
+ int stderr_fd = proc->GetStderrFileDescriptor();
+ if (stdout_fd == stderr_fd)
+ stderr_fd = -1;
+
+ while (stdout_fd >= 0 || stderr_fd >= 0)
+ {
+ ::pthread_testcancel ();
+
+ fd_set read_fds;
+ FD_ZERO (&read_fds);
+ if (stdout_fd >= 0)
+ FD_SET (stdout_fd, &read_fds);
+ if (stderr_fd >= 0)
+ FD_SET (stderr_fd, &read_fds);
+ int nfds = std::max<int>(stdout_fd, stderr_fd) + 1;
+
+ int num_set_fds = select (nfds, &read_fds, NULL, NULL, NULL);
+ if (log)
+ log->Printf("select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
+
+ if (num_set_fds < 0)
+ {
+ int select_errno = errno;
+ if (log)
+ {
+ err.SetError (select_errno, Error::POSIX);
+ err.LogIfError(log, "select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
+ }
+
+ switch (select_errno)
+ {
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to allocate the requested number of file descriptors, or we have non-blocking IO
+ break;
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ return NULL;
+ break;
+ case EINTR: // A signal was delivered before the time limit expired and before any of the selected events occurred.
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
+ break;
+ }
+ }
+ else if (num_set_fds == 0)
+ {
+ }
+ else
+ {
+ char s[1024];
+ s[sizeof(s)-1] = '\0'; // Ensure we have NULL termination
+ int bytes_read = 0;
+ if (stdout_fd >= 0 && FD_ISSET (stdout_fd, &read_fds))
+ {
+ do
+ {
+ bytes_read = ::read (stdout_fd, s, sizeof(s)-1);
+ if (bytes_read < 0)
+ {
+ int read_errno = errno;
+ if (log)
+ log->Printf("read (stdout_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
+ }
+ else if (bytes_read == 0)
+ {
+ // EOF...
+ if (log)
+ log->Printf("read (stdout_fd, ) => %d (reached EOF for child STDOUT)", bytes_read);
+ stdout_fd = -1;
+ }
+ else if (bytes_read > 0)
+ {
+ proc->AppendSTDOUT(s, bytes_read);
+ }
+
+ } while (bytes_read > 0);
+ }
+
+ if (stderr_fd >= 0 && FD_ISSET (stderr_fd, &read_fds))
+ {
+ do
+ {
+ bytes_read = ::read (stderr_fd, s, sizeof(s)-1);
+ if (bytes_read < 0)
+ {
+ int read_errno = errno;
+ if (log)
+ log->Printf("read (stderr_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
+ }
+ else if (bytes_read == 0)
+ {
+ // EOF...
+ if (log)
+ log->Printf("read (stderr_fd, ) => %d (reached EOF for child STDERR)", bytes_read);
+ stderr_fd = -1;
+ }
+ else if (bytes_read > 0)
+ {
+ proc->AppendSTDOUT(s, bytes_read);
+ }
+
+ } while (bytes_read > 0);
+ }
+ }
+ }
+
+ if (log)
+ log->Printf("ProcessMacOSXRemote::%s (%p): thread exiting...", __FUNCTION__, arg);
+
+ return NULL;
+}
+
+lldb::pid_t
+ProcessMacOSXRemote::AttachForDebug (lldb::pid_t pid)
+{
+ // Clear out and clean up from any current state
+ Clear();
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+ if (pid != 0)
+ {
+ SetState(eStateAttaching);
+ SetID(pid);
+ // Let ourselves know we are going to be using SBS if the correct flag bit is set...
+#if defined (__arm__)
+ if (IsSBProcess(pid))
+ m_flags |= eFlagsUsingSBS;
+#endif
+ m_task.StartExceptionThread(GetError());
+
+ if (GetError().Success())
+ {
+ if (ptrace (PT_ATTACHEXC, pid, 0, 0) == 0)
+ {
+ m_flags.Set (eFlagsAttached);
+ // Sleep a bit to let the exception get received and set our process status
+ // to stopped.
+ ::usleep(250000);
+ if (log)
+ log->Printf ("successfully attached to pid %d", pid);
+ return GetID();
+ }
+ else
+ {
+ GetError().SetErrorToErrno();
+ if (log)
+ log->Printf ("error: failed to attach to pid %d", pid);
+ }
+ }
+ else
+ {
+ GetError().Log(log, "ProcessMacOSXRemote::%s (pid = %i) failed to start exception thread", __FUNCTION__, pid);
+ }
+ }
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+lldb::pid_t
+ProcessMacOSXRemote::LaunchForDebug
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ PDLaunchType launch_type,
+ Error &launch_err)
+{
+ // Clear out and clean up from any current state
+ Clear();
+
+ m_arch_spec = arch_spec;
+
+ if (launch_type == eLaunchDefault)
+ launch_type = eLaunchPosixSpawn;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+ if (log)
+ log->Printf ("%s( path = '%s', argv = %p, envp = %p, launch_type = %u )", __FUNCTION__, path, argv, envp, launch_type);
+
+ // Fork a child process for debugging
+ SetState(eStateLaunching);
+ switch (launch_type)
+ {
+ case eLaunchForkExec:
+ SetID(ProcessMacOSXRemote::ForkChildForPTraceDebugging(path, argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, this, launch_err));
+ break;
+
+ case eLaunchPosixSpawn:
+ SetID(ProcessMacOSXRemote::PosixSpawnChildForPTraceDebugging(path, argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, this, launch_err));
+ break;
+
+#if defined (__arm__)
+
+ case eLaunchSpringBoard:
+ {
+ const char *app_ext = strstr(path, ".app");
+ if (app_ext != NULL)
+ {
+ std::string app_bundle_path(path, app_ext + strlen(".app"));
+ return SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, arch_spec, stdin_path, stdout_path, stderr_path, launch_err);
+ }
+ }
+ break;
+
+#endif
+
+ default:
+ // Invalid launch
+ launch_err.SetErrorToGenericError ();
+ return LLDB_INVALID_PROCESS_ID;
+ }
+
+ lldb::pid_t pid = GetID();
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // If we don't have a valid process ID and no one has set the error,
+ // then return a generic error
+ if (launch_err.Success())
+ launch_err.SetErrorToGenericError ();
+ }
+ else
+ {
+ // Make sure we can get our task port before going any further
+ m_task.TaskPortForProcessID (launch_err);
+
+ // If that goes well then kick off our exception thread
+ if (launch_err.Success())
+ m_task.StartExceptionThread(launch_err);
+
+ if (launch_err.Success())
+ {
+ //m_path = path;
+// size_t i;
+// if (argv)
+// {
+// char const *arg;
+// for (i=0; (arg = argv[i]) != NULL; i++)
+// m_args.push_back(arg);
+// }
+
+ StartSTDIOThread();
+
+ if (launch_type == eLaunchPosixSpawn)
+ {
+
+ //SetState (eStateAttaching);
+ errno = 0;
+ if (::ptrace (PT_ATTACHEXC, pid, 0, 0) == 0)
+ launch_err.Clear();
+ else
+ launch_err.SetErrorToErrno();
+
+ if (launch_err.Fail() || log)
+ launch_err.Log(log, "::ptrace (PT_ATTACHEXC, pid = %i, 0, 0 )", pid);
+
+ if (launch_err.Success())
+ m_flags.Set (eFlagsAttached);
+ else
+ SetState (eStateExited);
+ }
+ else
+ {
+ launch_err.Clear();
+ }
+ }
+ else
+ {
+ // We were able to launch the process, but not get its task port
+ // so now we need to make it sleep with da fishes.
+ SetID(LLDB_INVALID_PROCESS_ID);
+ ::kill (pid, SIGCONT);
+ ::kill (pid, SIGKILL);
+ pid = LLDB_INVALID_PROCESS_ID;
+ }
+
+ }
+ return pid;
+}
+
+lldb::pid_t
+ProcessMacOSXRemote::PosixSpawnChildForPTraceDebugging
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSXRemote* process,
+ Error &err
+)
+{
+ posix_spawnattr_t attr;
+
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_PROCESS);
+
+ Error local_err; // Errors that don't affect the spawning.
+ if (log)
+ log->Printf ("%s ( path='%s', argv=%p, envp=%p, process )", __FUNCTION__, path, argv, envp);
+ err.SetError( ::posix_spawnattr_init (&attr), Error::POSIX);
+ if (err.Fail() || log)
+ err.Log(log, "::posix_spawnattr_init ( &attr )");
+ if (err.Fail())
+ return LLDB_INVALID_PROCESS_ID;
+
+ err.SetError( ::posix_spawnattr_setflags (&attr, POSIX_SPAWN_START_SUSPENDED), Error::POSIX);
+ if (err.Fail() || log)
+ err.Log(log, "::posix_spawnattr_setflags ( &attr, POSIX_SPAWN_START_SUSPENDED )");
+ if (err.Fail())
+ return LLDB_INVALID_PROCESS_ID;
+
+#if !defined(__arm__)
+
+ // We don't need to do this for ARM, and we really shouldn't now that we
+ // have multiple CPU subtypes and no posix_spawnattr call that allows us
+ // to set which CPU subtype to launch...
+ cpu_type_t cpu = arch_spec.GetCPUType();
+ if (cpu != 0 && cpu != CPU_TYPE_ANY && cpu != LLDB_INVALID_CPUTYPE)
+ {
+ size_t ocount = 0;
+ err.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), Error::POSIX);
+ if (err.Fail() || log)
+ err.Log(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %zu )", cpu, ocount);
+
+ if (err.Fail() != 0 || ocount != 1)
+ return LLDB_INVALID_PROCESS_ID;
+ }
+
+#endif
+
+ PseudoTerminal pty;
+
+ posix_spawn_file_actions_t file_actions;
+ err.SetError( ::posix_spawn_file_actions_init (&file_actions), Error::POSIX);
+ int file_actions_valid = err.Success();
+ if (!file_actions_valid || log)
+ err.Log(log, "::posix_spawn_file_actions_init ( &file_actions )");
+ Error stdio_err;
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ if (file_actions_valid)
+ {
+ // If the user specified any STDIO files, then use those
+ if (stdin_path || stdout_path || stderr_path)
+ {
+ process->SetSTDIOIsOurs(false);
+ if (stderr_path != NULL && stderr_path[0])
+ {
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDERR_FILENO, stderr_path, O_RDWR, 0), Error::POSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.Log(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDERR_FILENO, path = '%s', oflag = O_RDWR, mode = 0 )", stderr_path);
+ }
+
+ if (stdin_path != NULL && stdin_path[0])
+ {
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDIN_FILENO, stdin_path, O_RDONLY, 0), Error::POSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.Log(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDIN_FILENO, path = '%s', oflag = O_RDONLY, mode = 0 )", stdin_path);
+ }
+
+ if (stdout_path != NULL && stdout_path[0])
+ {
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDOUT_FILENO, stdout_path, O_WRONLY, 0), Error::POSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.Log(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDOUT_FILENO, path = '%s', oflag = O_WRONLY, mode = 0 )", stdout_path);
+ }
+ }
+ else
+ {
+ // The user did not specify any STDIO files, use a pseudo terminal.
+ // Callers can then access the file handles using the
+ // ProcessMacOSXRemote::ReleaseChildFileDescriptors() function, otherwise
+ // this class will spawn a thread that tracks STDIO and buffers it.
+ process->SetSTDIOIsOurs(true);
+ if (pty.OpenFirstAvailableMaster(O_RDWR, &stdio_err))
+ {
+ const char* slave_name = pty.GetSlaveName(&stdio_err);
+ if (slave_name == NULL)
+ slave_name = "/dev/null";
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDERR_FILENO, slave_name, O_RDWR, 0), Error::POSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.Log(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDERR_FILENO, path = '%s', oflag = O_RDWR, mode = 0 )", slave_name);
+
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDIN_FILENO, slave_name, O_RDONLY, 0), Error::POSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.Log(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDIN_FILENO, path = '%s', oflag = O_RDONLY, mode = 0 )", slave_name);
+
+ stdio_err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDOUT_FILENO, slave_name, O_WRONLY, 0), Error::POSIX);
+ if (stdio_err.Fail() || log)
+ stdio_err.Log(log, "::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDOUT_FILENO, path = '%s', oflag = O_WRONLY, mode = 0 )", slave_name);
+ }
+ }
+ err.SetError( ::posix_spawnp (&pid, path, &file_actions, &attr, (char * const*)argv, (char * const*)envp), Error::POSIX);
+ if (err.Fail() || log)
+ err.Log(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, &file_actions, &attr, argv, envp);
+
+ if (stdio_err.Success())
+ {
+ // If we have a valid process and we created the STDIO file handles,
+ // then remember them on our process class so we can spawn a STDIO
+ // thread and close them when we are done with them.
+ if (process != NULL && process->STDIOIsOurs())
+ {
+ int master_fd = pty.ReleaseMasterFileDescriptor ();
+ process->SetChildFileDescriptors (master_fd, master_fd, master_fd);
+ }
+ }
+ }
+ else
+ {
+ err.SetError( ::posix_spawnp (&pid, path, NULL, &attr, (char * const*)argv, (char * const*)envp), Error::POSIX);
+ if (err.Fail() || log)
+ err.Log(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, NULL, &attr, argv, envp);
+ }
+
+ // We have seen some cases where posix_spawnp was returning a valid
+ // looking pid even when an error was returned, so clear it out
+ if (err.Fail())
+ pid = LLDB_INVALID_PROCESS_ID;
+
+ if (file_actions_valid)
+ {
+ local_err.SetError( ::posix_spawn_file_actions_destroy (&file_actions), Error::POSIX);
+ if (local_err.Fail() || log)
+ local_err.Log(log, "::posix_spawn_file_actions_destroy ( &file_actions )");
+ }
+
+ return pid;
+}
+
+lldb::pid_t
+ProcessMacOSXRemote::ForkChildForPTraceDebugging
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSXRemote* process,
+ Error &launch_err
+)
+{
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ if (stdin_path || stdout_path || stderr_path)
+ {
+ assert(!"TODO: ForkChildForPTraceDebugging doesn't currently support fork/exec with user file handles...");
+ }
+ else
+ {
+
+ // Use a fork that ties the child process's stdin/out/err to a pseudo
+ // terminal so we can read it in our ProcessMacOSXRemote::STDIOThread
+ // as unbuffered io.
+ PseudoTerminal pty;
+ pid = pty.Fork(&launch_err);
+
+ if (pid < 0)
+ {
+ //--------------------------------------------------------------
+ // Error during fork.
+ //--------------------------------------------------------------
+ return pid;
+ }
+ else if (pid == 0)
+ {
+ //--------------------------------------------------------------
+ // Child process
+ //--------------------------------------------------------------
+ ::ptrace (PT_TRACE_ME, 0, 0, 0); // Debug this process
+ ::ptrace (PT_SIGEXC, 0, 0, 0); // Get BSD signals as mach exceptions
+
+ // If our parent is setgid, lets make sure we don't inherit those
+ // extra powers due to nepotism.
+ ::setgid (getgid ());
+
+ // Let the child have its own process group. We need to execute
+ // this call in both the child and parent to avoid a race condition
+ // between the two processes.
+ ::setpgid (0, 0); // Set the child process group to match its pid
+
+ // Sleep a bit to before the exec call
+ ::sleep (1);
+
+ // Turn this process into
+ ::execv (path, (char * const *)argv);
+ // Exit with error code. Child process should have taken
+ // over in above exec call and if the exec fails it will
+ // exit the child process below.
+ ::exit (127);
+ }
+ else
+ {
+ //--------------------------------------------------------------
+ // Parent process
+ //--------------------------------------------------------------
+ // Let the child have its own process group. We need to execute
+ // this call in both the child and parent to avoid a race condition
+ // between the two processes.
+ ::setpgid (pid, pid); // Set the child process group to match its pid
+
+ if (process != NULL)
+ {
+ // Release our master pty file descriptor so the pty class doesn't
+ // close it and so we can continue to use it in our STDIO thread
+ int master_fd = pty.ReleaseMasterFileDescriptor ();
+ process->SetChildFileDescriptors (master_fd, master_fd, master_fd);
+ }
+ }
+ }
+ return pid;
+}
+
+#if defined (__arm__)
+
+lldb::pid_t
+ProcessMacOSXRemote::SBLaunchForDebug
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ Error &launch_err
+)
+{
+ // Clear out and clean up from any current state
+ Clear();
+
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path);
+
+ // Fork a child process for debugging
+ SetState(eStateLaunching);
+ m_pid = ProcessMacOSXRemote::SBLaunchForDebug(path, argv, envp, this, launch_err);
+ if (m_pid != 0)
+ {
+ m_flags |= eFlagsUsingSBS;
+ //m_path = path;
+// size_t i;
+// char const *arg;
+// for (i=0; (arg = argv[i]) != NULL; i++)
+// m_args.push_back(arg);
+ m_task.StartExceptionThread();
+ StartSTDIOThread();
+ SetState (eStateAttaching);
+ int err = ptrace (PT_ATTACHEXC, m_pid, 0, 0);
+ if (err == 0)
+ {
+ m_flags |= eFlagsAttached;
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "successfully attached to pid %d", m_pid);
+ }
+ else
+ {
+ SetState (eStateExited);
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "error: failed to attach to pid %d", m_pid);
+ }
+ }
+ return m_pid;
+}
+
+#include <servers/bootstrap.h>
+#include "CFBundle.h"
+#include "CFData.h"
+#include "CFString.h"
+
+lldb::pid_t
+ProcessMacOSXRemote::SBLaunchForDebug
+(
+ const char *app_bundle_path,
+ char const *argv[],
+ char const *envp[],
+ ArchSpec& arch_spec,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ ProcessMacOSXRemote* process,
+ Error &launch_err
+)
+{
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, app_bundle_path, process);
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+ if (argv[0] == NULL)
+ return LLDB_INVALID_PROCESS_ID;
+
+ size_t argc = 0;
+ // Count the number of arguments
+ while (argv[argc] != NULL)
+ argc++;
+
+ // Enumerate the arguments
+ size_t first_launch_arg_idx = 1;
+ CFReleaser<CFMutableArrayRef> launch_argv;
+
+ if (argv[first_launch_arg_idx])
+ {
+ size_t launch_argc = argc > 0 ? argc - 1 : 0;
+ launch_argv.reset (::CFArrayCreateMutable (alloc, launch_argc, &kCFTypeArrayCallBacks));
+ size_t i;
+ char const *arg;
+ CFString launch_arg;
+ for (i=first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); i++)
+ {
+ launch_arg.reset(::CFStringCreateWithCString (alloc, arg, kCFStringEncodingUTF8));
+ if (launch_arg.get() != NULL)
+ CFArrayAppendValue(launch_argv.get(), launch_arg.get());
+ else
+ break;
+ }
+ }
+
+ // Next fill in the arguments dictionary. Note, the envp array is of the form
+ // Variable=value but SpringBoard wants a CF dictionary. So we have to convert
+ // this here.
+
+ CFReleaser<CFMutableDictionaryRef> launch_envp;
+
+ if (envp[0])
+ {
+ launch_envp.reset(::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+ const char *value;
+ int name_len;
+ CFString name_string, value_string;
+
+ for (int i = 0; envp[i] != NULL; i++)
+ {
+ value = strstr (envp[i], "=");
+
+ // If the name field is empty or there's no =, skip it. Somebody's messing with us.
+ if (value == NULL || value == envp[i])
+ continue;
+
+ name_len = value - envp[i];
+
+ // Now move value over the "="
+ value++;
+
+ name_string.reset(::CFStringCreateWithBytes(alloc, (const UInt8 *) envp[i], name_len, kCFStringEncodingUTF8, false));
+ value_string.reset(::CFStringCreateWithCString(alloc, value, kCFStringEncodingUTF8));
+ CFDictionarySetValue (launch_envp.get(), name_string.get(), value_string.get());
+ }
+ }
+
+ CFString stdout_cf_path;
+ CFString stderr_cf_path;
+ PseudoTerminal pty;
+
+ if (stdin_path || stdout_path || stderr_path)
+ {
+ process->SetSTDIOIsOurs(false);
+ if (stdout_path)
+ stdout_cf_path.SetFileSystemRepresentation (stdout_path);
+ if (stderr_path)
+ stderr_cf_path.SetFileSystemRepresentation (stderr_path);
+ }
+ else
+ {
+ process->SetSTDIOIsOurs(true);
+ PseudoTerminal::Error pty_err = pty.OpenFirstAvailableMaster(O_RDWR);
+ if (pty_err == PseudoTerminal::success)
+ {
+ const char* slave_name = pty.SlaveName();
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() successfully opened master pty, slave is %s", __FUNCTION__, slave_name);
+ if (slave_name && slave_name[0])
+ {
+ ::chmod (slave_name, S_IRWXU | S_IRWXG | S_IRWXO);
+ stdout_cf_path.SetFileSystemRepresentation (slave_name);
+ stderr_cf_path.(stdout_cf_path);
+ }
+ }
+ }
+
+ if (stdout_cf_path.get() == NULL)
+ stdout_cf_path.SetFileSystemRepresentation ("/dev/null");
+ if (stderr_cf_path.get() == NULL)
+ stderr_cf_path.SetFileSystemRepresentation ("/dev/null");
+
+ CFBundle bundle(app_bundle_path);
+ CFStringRef bundleIDCFStr = bundle.GetIdentifier();
+ std::string bundleID;
+ if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL)
+ {
+ struct stat app_bundle_stat;
+ if (::stat (app_bundle_path, &app_bundle_stat) < 0)
+ {
+ launch_err.SetError(errno, Error::POSIX);
+ launch_err.SetErrorStringWithFormat ("%s: \"%s\".\n", launch_err.AsString(), app_bundle_path);
+ }
+ else
+ {
+ launch_err.SetError(-1, Error::Generic);
+ launch_err.SetErrorStringWithFormat ("Failed to extract CFBundleIdentifier from %s.\n", app_bundle_path);
+ }
+ return LLDB_INVALID_PROCESS_ID;
+ }
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", __FUNCTION__, bundleID.c_str());
+
+
+ CFData argv_data(NULL);
+
+ if (launch_argv.get())
+ {
+ if (argv_data.Serialize(launch_argv.get(), kCFPropertyListBinaryFormat_v1_0) == NULL)
+ {
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() error: failed to serialize launch arg array...", __FUNCTION__);
+ return LLDB_INVALID_PROCESS_ID;
+ }
+ }
+
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() serialized launch arg array", __FUNCTION__);
+
+ // Find SpringBoard
+ SBSApplicationLaunchError sbs_error = 0;
+ sbs_error = SBSLaunchApplication ( bundleIDCFStr,
+ (CFURLRef)NULL, // openURL
+ launch_argv.get(),
+ launch_envp.get(), // CFDictionaryRef environment
+ stdout_cf_path.get(),
+ stderr_cf_path.get(),
+ SBSApplicationLaunchWaitForDebugger | SBSApplicationLaunchUnlockDevice);
+
+
+ launch_err.SetError(sbs_error, Error::SpringBoard);
+
+ if (sbs_error == SBSApplicationLaunchErrorSuccess)
+ {
+ static const useconds_t pid_poll_interval = 200000;
+ static const useconds_t pid_poll_timeout = 30000000;
+
+ useconds_t pid_poll_total = 0;
+
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ Boolean pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
+ // Poll until the process is running, as long as we are getting valid responses and the timeout hasn't expired
+ // A return PID of 0 means the process is not running, which may be because it hasn't been (asynchronously) started
+ // yet, or that it died very quickly (if you weren't using waitForDebugger).
+ while (!pid_found && pid_poll_total < pid_poll_timeout)
+ {
+ usleep (pid_poll_interval);
+ pid_poll_total += pid_poll_interval;
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() polling Springboard for pid for %s...", __FUNCTION__, bundleID.c_str());
+ pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
+ }
+
+ if (pid_found)
+ {
+ // If we have a valid process and we created the STDIO file handles,
+ // then remember them on our process class so we can spawn a STDIO
+ // thread and close them when we are done with them.
+ if (process != NULL && process->STDIOIsOurs())
+ {
+ // Release our master pty file descriptor so the pty class doesn't
+ // close it and so we can continue to use it in our STDIO thread
+ int master_fd = pty.ReleaseMasterFD();
+ process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
+ }
+ ProcessMacOSXLog::LogIf (PD_LOG_PROCESS, "%s() => pid = %4.4x", __FUNCTION__, pid);
+ }
+ else
+ {
+ LogError("failed to lookup the process ID for CFBundleIdentifier %s.", bundleID.c_str());
+ }
+ return pid;
+ }
+
+ LogError("unable to launch the application with CFBundleIdentifier '%s' sbs_error = %u", bundleID.c_str(), sbs_error);
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+#endif // #if defined (__arm__)
+
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.h b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.h
new file mode 100644
index 00000000000..01905c6192a
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSXRemote.h
@@ -0,0 +1,206 @@
+//===-- ProcessMacOSXRemote.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// ProcessMacOSXRemote.h
+// liblldb
+//
+// Created by Greg Clayton on 4/21/09.
+//
+//
+//----------------------------------------------------------------------
+
+#ifndef liblldb_ProcessMacOSXRemote_H_
+#define liblldb_ProcessMacOSXRemote_H_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+
+// Other libraries and framework includes
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+class ThreadMacOSXRemote;
+
+class ProcessMacOSXRemote :
+ public Process
+{
+public:
+ friend class ThreadMacOSX;
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessMacOSXRemote(Target& target);
+ virtual ~DCProcessMacOSXRemote();
+
+ static Process* CreateInstance (Target& target);
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ virtual bool CanDebug(Target &target);
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ virtual lldb::pid_t DoLaunch (Module* module,
+ char const *argv[], // Can be NULL
+ char const *envp[], // Can be NULL
+ const char *stdin_path, // Can be NULL
+ const char *stdout_path, // Can be NULL
+ const char *stderr_path); // Can be NULL
+ virtual void DidLaunch ();
+ virtual lldb::pid_t DoAttach (lldb::pid_t pid);
+ virtual void DidAttach ();
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+// virtual bool WillResume ();
+ virtual bool DoResume ();
+// virtual void DidResume ();
+
+ virtual bool DoHalt ();
+ virtual bool WillDetach ();
+ virtual bool DoDetach ();
+ virtual bool DoKill (int signal);
+
+ virtual bool ShouldStop ();
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ virtual bool IsAlive ();
+ virtual bool IsRunning ();
+ virtual lldb::addr_t GetImageInfoAddress();
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ virtual size_t DoReadMemory (lldb::addr_t addr, void *buf, size_t size);
+ virtual size_t DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size);
+
+ //------------------------------------------------------------------
+ // Process STDIO
+ //------------------------------------------------------------------
+ virtual size_t GetSTDOUT (char *buf, size_t buf_size);
+ virtual size_t GetSTDERR (char *buf, size_t buf_size);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode (lldb::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual bool
+ EnableBreakpoint (lldb::BreakpointSite *bp_site);
+
+ virtual bool
+ DisableBreakpoint (lldb::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Watchpoints
+ //----------------------------------------------------------------------
+ virtual bool EnableWatchpoint (WatchpointLocation *wp_loc);
+ virtual bool DisableWatchpoint (WatchpointLocation *wp_loc);
+
+ //------------------------------------------------------------------
+ // Thread Queries
+ //------------------------------------------------------------------
+ virtual Thread * GetCurrentThread ();
+ virtual bool SetCurrentThread (lldb::tid_t tid);
+ virtual Thread * GetThreadAtIndex (uint32_t idx);
+ virtual Thread * GetThreadByID (lldb::tid_t tid);
+ virtual size_t GetNumThreads ();
+
+ virtual ByteOrder GetByteOrder () const;
+
+ virtual DynamicLoader *
+ GetDynamicLoader ();
+
+protected:
+ Flags m_flags; // Process specific flags (see eFlags enums)
+ ArchSpec m_arch_spec;
+ std::auto_ptr<DynamicLoader> m_dynamic_loader_ap;
+ ByteOrder m_byte_order;
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ bool
+ ProcessIDIsValid ( ) const;
+
+ bool
+ IsRunning ( State state )
+ {
+ return state == eStateRunning || IsStepping(state);
+ }
+
+ bool
+ IsStepping ( State state)
+ {
+ return state == eStateStepping;
+ }
+ bool
+ CanResume ( State state)
+ {
+ return state == eStateStopped;
+ }
+
+ ArchSpec&
+ GetArchSpec()
+ {
+ return m_arch_spec;
+ }
+ const ArchSpec&
+ GetArchSpec() const
+ {
+ return m_arch_spec;
+ }
+
+ enum
+ {
+ eFlagsNone = 0,
+ eFlagsAttached = (1 << 0),
+ eFlagsUsingSBS = (1 << 1)
+ };
+
+ void
+ Clear ( );
+
+ Flags &
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const Flags &
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ uint32_t
+ UpdateThreadListIfNeeded ();
+
+private:
+ //------------------------------------------------------------------
+ // For ProcessMacOSXRemote only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ProcessMacOSXRemote);
+
+};
+
+#endif // liblldb_ProcessMacOSXRemote_H_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.cpp
new file mode 100644
index 00000000000..37472547f55
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.cpp
@@ -0,0 +1,1448 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMach_arm.h"
+
+// C Includes
+#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/Scalar.h"
+
+// Project includes
+#include "ARM_GCC_Registers.h"
+#include "ARM_DWARF_Registers.h"
+#include "ProcessMacOSXLog.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
+};
+
+
+RegisterContextMach_arm::RegisterContextMach_arm(Thread &thread, StackFrame *frame) :
+ RegisterContext(thread, frame),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextMach_arm::~RegisterContextMach_arm()
+{
+}
+
+
+#define GPR_OFFSET(idx) ((idx) * 4)
+#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextMach_arm::GPR))
+#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextMach_arm::GPR) + sizeof (RegisterContextMach_arm::FPU))
+#define DBG_OFFSET(reg) (offsetof (RegisterContextMach_arm::DBG, reg) + sizeof (RegisterContextMach_arm::GPR) + sizeof (RegisterContextMach_arm::FPU) + sizeof (RegisterContextMach_arm::EXC))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextMach_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, dbg_##reg##i, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextMach_arm::GPR) + sizeof (RegisterContextMach_arm::FPU) + sizeof (RegisterContextMach_arm::EXC))
+// General purpose registers
+static lldb::RegisterInfo
+g_register_infos[] =
+{
+// NAME ALT SZ OFFSET ENCODING FORMAT NATIVE COMPILER DWARF GENERIC
+// ====== ======= == ============= ============= ============ ========== =============== =============== =========
+{ "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, gpr_r0, { gcc_r0, dwarf_r0, LLDB_INVALID_REGNUM }},
+{ "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, gpr_r1, { gcc_r1, dwarf_r1, LLDB_INVALID_REGNUM }},
+{ "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, gpr_r2, { gcc_r2, dwarf_r2, LLDB_INVALID_REGNUM }},
+{ "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, gpr_r3, { gcc_r3, dwarf_r3, LLDB_INVALID_REGNUM }},
+{ "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, gpr_r4, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM }},
+{ "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, gpr_r5, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM }},
+{ "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, gpr_r6, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM }},
+{ "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, gpr_r7, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP }},
+{ "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, gpr_r8, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM }},
+{ "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, gpr_r9, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM }},
+{ "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, gpr_r10, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM }},
+{ "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, gpr_r11, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM }},
+{ "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, gpr_r12, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM }},
+{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, gpr_sp, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP }},
+{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, gpr_lr, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA }},
+{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, gpr_pc, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC }},
+{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, gpr_cpsr, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS }},
+
+{ "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, fpu_s0, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM }},
+{ "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, fpu_s1, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM }},
+{ "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, fpu_s2, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM }},
+{ "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, fpu_s3, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM }},
+{ "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, fpu_s4, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM }},
+{ "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, fpu_s5, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM }},
+{ "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, fpu_s6, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM }},
+{ "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, fpu_s7, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM }},
+{ "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, fpu_s8, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM }},
+{ "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, fpu_s9, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM }},
+{ "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, fpu_s10, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM }},
+{ "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, fpu_s11, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM }},
+{ "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, fpu_s12, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM }},
+{ "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, fpu_s13, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM }},
+{ "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, fpu_s14, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM }},
+{ "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, fpu_s15, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM }},
+{ "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, fpu_s16, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM }},
+{ "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, fpu_s17, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM }},
+{ "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, fpu_s18, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM }},
+{ "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, fpu_s19, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM }},
+{ "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, fpu_s20, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM }},
+{ "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, fpu_s21, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM }},
+{ "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, fpu_s22, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM }},
+{ "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, fpu_s23, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM }},
+{ "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, fpu_s24, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM }},
+{ "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, fpu_s25, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM }},
+{ "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, fpu_s26, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM }},
+{ "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, fpu_s27, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM }},
+{ "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, fpu_s28, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM }},
+{ "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, fpu_s29, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM }},
+{ "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, fpu_s30, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM }},
+{ "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, fpu_s31, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM }},
+{ "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, fpu_fpscr, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }},
+
+{ "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, exc_exception,{ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }},
+{ "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, exc_fsr, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }},
+{ "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, exc_far, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }},
+
+{ DEFINE_DBG (bvr, 0) },
+{ 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, 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, 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, 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
+RegisterContextMach_arm::Invalidate ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextMach_arm::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextMach_arm::GetRegisterInfoAtIndex (uint32_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextMach_arm::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextMach_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
+RegisterContextMach_arm::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextMach_arm::GetRegisterSet (uint32_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
+RegisterContextMach_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;
+}
+
+kern_return_t
+RegisterContextMach_arm::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = GPRWordCount;
+ SetError(GPRRegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&gpr, &count));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_arm::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = FPUWordCount;
+ SetError(FPURegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&fpu, &count));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_arm::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = EXCWordCount;
+ SetError(EXCRegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&exc, &count));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_arm::ReadDBG (bool force)
+{
+ int set = DBGRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = DBGWordCount;
+ SetError(DBGRegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&dbg, &count));
+ }
+ return GetError(DBGRegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_arm::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(GPRRegSet, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&gpr, GPRWordCount));
+ return GetError(GPRRegSet, Write);
+}
+
+kern_return_t
+RegisterContextMach_arm::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(FPURegSet, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&fpu, FPUWordCount));
+ return GetError(FPURegSet, Write);
+}
+
+kern_return_t
+RegisterContextMach_arm::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(EXCRegSet, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&exc, EXCWordCount));
+ return GetError(EXCRegSet, Write);
+}
+
+kern_return_t
+RegisterContextMach_arm::WriteDBG ()
+{
+ int set = DBGRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(DBGRegSet, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&dbg, DBGWordCount));
+ return GetError(DBGRegSet, Write);
+}
+
+
+kern_return_t
+RegisterContextMach_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;
+}
+
+kern_return_t
+RegisterContextMach_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
+RegisterContextMach_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
+RegisterContextMach_arm::ReadRegisterValue (uint32_t reg, Scalar &value)
+{
+ int set = RegisterContextMach_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 = 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 = fpu.floats.s[reg];
+ break;
+
+ case fpu_fpscr:
+ value = fpu.fpscr;
+ break;
+
+ case exc_exception:
+ value = exc.exception;
+ break;
+ case exc_fsr:
+ value = exc.fsr;
+ break;
+ case exc_far:
+ value = exc.far;
+ break;
+
+ default:
+ return false;
+
+ }
+ return true;
+}
+
+
+bool
+RegisterContextMach_arm::WriteRegisterValue (uint32_t reg, const Scalar &value)
+{
+ 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.UInt(0);
+ 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.UInt(0);
+ break;
+
+ case fpu_fpscr:
+ fpu.fpscr = value.UInt(0);
+ break;
+
+ case exc_exception:
+ exc.exception = value.UInt(0);
+ break;
+ case exc_fsr:
+ exc.fsr = value.UInt(0);
+ break;
+ case exc_far:
+ exc.far = value.UInt(0);
+ break;
+
+ default:
+ return false;
+
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextMach_arm::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
+{
+ int set = RegisterContextMach_arm::GetSetForNativeRegNum (reg);
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ 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:
+ data.SetData(&gpr.r[reg - gpr_r0], reg_info->byte_size, eByteOrderHost);
+ 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:
+ data.SetData(&fpu.floats.s[reg - fpu_s0], reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fpscr:
+ data.SetData(&fpu.fpscr, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_exception:
+ data.SetData(&exc.exception, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_fsr:
+ data.SetData(&exc.fsr, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_far:
+ data.SetData(&exc.far, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool
+RegisterContextMach_arm::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
+{
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL && data.ValidOffsetForDataOfSize(data_offset, reg_info->byte_size))
+ return false;
+
+ uint32_t offset = data_offset;
+ 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] = data.GetU32 (&offset);
+ 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 - fpu_s0] = data.GetU32 (&offset);
+ break;
+
+ case fpu_fpscr:
+ fpu.fpscr = data.GetU32 (&offset);
+ break;
+
+ case exc_exception:
+ fpu.fpscr = data.GetU32 (&offset);
+ break;
+
+ case exc_fsr:
+ exc.fsr = data.GetU32 (&offset);
+ break;
+
+ case exc_far:
+ exc.far = data.GetU32 (&offset);
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextMach_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
+RegisterContextMach_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
+RegisterContextMach_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;
+ }
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+uint32_t
+RegisterContextMach_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 = UINT_MAX
+ if (g_num_supported_hw_breakpoints == UINT_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_breakpoints = 0;
+
+ // Read the DBGDIDR to get the number of available hardware breakpoints
+ // However, in some of our current armv7 processors, hardware
+ // breakpoints/watchpoints were not properly connected. So detect those
+ // cases using a field in a sysctl. For now we are using "hw.cpusubtype"
+ // field to distinguish CPU architectures. This is a hack until we can
+ // get <rdar://problem/6372672> fixed, at which point we will switch to
+ // using a different sysctl string that will tell us how many BRPs
+ // are available to us directly without having to read DBGDIDR.
+ uint32_t register_DBGDIDR;
+
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ uint32_t numBRPs = bits(register_DBGDIDR, 27, 24);
+ // Zero is reserved for the BRP count, so don't increment it if it is zero
+ if (numBRPs > 0)
+ numBRPs++;
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "DBGDIDR=0x%8.8x (number BRP pairs = %u)", register_DBGDIDR, numBRPs);
+
+ if (numBRPs > 0)
+ {
+ uint32_t cpu_subtype;
+ size_t len;
+ len = sizeof(cpusubtype);
+ // TODO: remove this hack and change to using hw.optional.xx when implmented
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "hw.cpusubtype=0x%d", cpusubtype);
+ if (cpusubtype == CPU_SUBTYPE_ARM_V7)
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "Hardware breakpoints disabled for armv7 (rdar://problem/6372672)");
+ else
+ g_num_supported_hw_breakpoints = numBRPs;
+ }
+ }
+
+ }
+ return g_num_supported_hw_breakpoints;
+#else
+ // TODO: figure out remote case here!
+ return 6;
+#endif
+}
+
+uint32_t
+RegisterContextMach_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ // Make sure our address isn't bogus
+ if (addr & 1)
+ return LLDB_INVALID_INDEX32;
+
+ kern_return_t 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
+ ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextMach_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
+ ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextMach_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();
+ ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextMach_arm::EnableHardwareBreakpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextMach_arm::EnableHardwareBreakpoint(addr = %8.8p, size = %u) => all hardware breakpoint resources are being used.", addr, size);
+ }
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextMach_arm::ClearHardwareBreakpoint (uint32_t hw_index)
+{
+ kern_return_t 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;
+ ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextMach_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
+RegisterContextMach_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 = UINT_MAX;
+ if (g_num_supported_hw_watchpoints == UINT_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_watchpoints = 0;
+ // Read the DBGDIDR to get the number of available hardware breakpoints
+ // However, in some of our current armv7 processors, hardware
+ // breakpoints/watchpoints were not properly connected. So detect those
+ // cases using a field in a sysctl. For now we are using "hw.cpusubtype"
+ // field to distinguish CPU architectures. This is a hack until we can
+ // get <rdar://problem/6372672> fixed, at which point we will switch to
+ // using a different sysctl string that will tell us how many WRPs
+ // are available to us directly without having to read DBGDIDR.
+
+ uint32_t register_DBGDIDR;
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ uint32_t numWRPs = bits(register_DBGDIDR, 31, 28) + 1;
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "DBGDIDR=0x%8.8x (number WRP pairs = %u)", register_DBGDIDR, numWRPs);
+
+ if (numWRPs > 0)
+ {
+ uint32_t cpusubtype;
+ size_t len;
+ len = sizeof(cpusubtype);
+ // TODO: remove this hack and change to using hw.optional.xx when implmented
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "hw.cpusubtype=0x%d", cpusubtype);
+
+ if (cpusubtype == CPU_SUBTYPE_ARM_V7)
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "Hardware watchpoints disabled for armv7 (rdar://problem/6372672)");
+ else
+ g_num_supported_hw_watchpoints = numWRPs;
+ }
+ }
+
+ }
+ return g_num_supported_hw_watchpoints;
+#else
+ // TODO: figure out remote case here!
+ return 2;
+#endif
+}
+
+
+uint32_t
+RegisterContextMach_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+ ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextMach_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;
+ ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextMach_arm::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset);
+
+ uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset;
+ ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextMach_arm::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask);
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Read the debug state
+ kern_return_t 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();
+ ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextMach_arm::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+ ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextMach_arm::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextMach_arm::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ kern_return_t 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;
+ ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextMach_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;
+}
+
+
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.h b/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.h
new file mode 100644
index 00000000000..37821cdd536
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_arm.h
@@ -0,0 +1,302 @@
+//===-- 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 "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 priveleged 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 RegisterContextMach_arm : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextMach_arm(lldb_private::Thread &thread, lldb_private::StackFrame *frame);
+
+ virtual
+ ~RegisterContextMach_arm();
+
+ virtual void
+ Invalidate ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb::RegisterSet *
+ GetRegisterSet (uint32_t set);
+
+ virtual bool
+ ReadRegisterValue (uint32_t reg, lldb_private::Scalar &value);
+
+ virtual bool
+ ReadRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegisterValue (uint32_t reg, const lldb_private::Scalar &value);
+
+ virtual bool
+ WriteRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data, uint32_t data_offset = 0);
+
+ 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 FPU
+ {
+ union {
+ uint32_t s[32];
+ uint64_t d[16];
+ } 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:
+
+ typedef enum
+ {
+ GPRRegSet = 1,
+ FPURegSet = 2,
+ EXCRegSet = 3,
+ DBGRegSet = 4,
+ };
+
+ 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;
+ kern_return_t gpr_errs[2]; // Read/Write errors
+ kern_return_t fpu_errs[2]; // Read/Write errors
+ kern_return_t exc_errs[2]; // Read/Write errors
+ kern_return_t dbg_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ kern_return_t
+ 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, kern_return_t 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) == KERN_SUCCESS;
+ }
+
+ kern_return_t
+ ReadGPR (bool force);
+
+ kern_return_t
+ ReadFPU (bool force);
+
+ kern_return_t
+ ReadEXC (bool force);
+
+ kern_return_t
+ ReadDBG (bool force);
+
+ kern_return_t
+ WriteGPR ();
+
+ kern_return_t
+ WriteFPU ();
+
+ kern_return_t
+ WriteEXC ();
+
+ kern_return_t
+ WriteDBG ();
+
+ kern_return_t
+ ReadRegisterSet (uint32_t set, bool force);
+
+ kern_return_t
+ 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::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextMach_arm_h_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.cpp
new file mode 100644
index 00000000000..daa4f0d4916
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.cpp
@@ -0,0 +1,1202 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+#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/Scalar.h"
+
+// Project includes
+#include "RegisterContextMach_i386.h"
+#include "ProcessMacOSXLog.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
+};
+
+RegisterContextMach_i386::RegisterContextMach_i386 (Thread &thread, StackFrame *frame) :
+ RegisterContext(thread, frame),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextMach_i386::~RegisterContextMach_i386()
+{
+}
+
+
+
+#define GPR_OFFSET(reg) (offsetof (RegisterContextMach_i386::GPR, reg))
+#define FPU_OFFSET(reg) (offsetof (RegisterContextMach_i386::FPU, reg) + sizeof (RegisterContextMach_i386::GPR))
+#define EXC_OFFSET(reg) (offsetof (RegisterContextMach_i386::EXC, reg) + sizeof (RegisterContextMach_i386::GPR) + sizeof (RegisterContextMach_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(((RegisterContextMach_i386::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex, gpr_##reg
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextMach_i386::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex, fpu_##reg
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextMach_i386::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, fpu_##reg##i, { LLDB_INVALID_REGNUM, dwarf_##reg##i, LLDB_INVALID_REGNUM, gdb_##reg##i }
+
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextMach_i386::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex, exc_##reg
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextMach_i386::GPR) + sizeof (RegisterContextMach_i386::FPU) + sizeof (RegisterContextMach_i386::EXC))
+
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC REG KIND NUM DWARF REG KIND NUM GENERIC REG KIND NUM GDB REG KIND NUM
+// =============================== ======================= =================== ========================== ==========================
+ { 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_REGNUM_GENERIC_FP , gdb_ebp }},
+ { DEFINE_GPR(esp , "sp") , { gcc_esp , dwarf_esp , LLDB_REGNUM_GENERIC_SP , 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_REGNUM_GENERIC_FLAGS , gdb_eflags }},
+ { DEFINE_GPR(eip , "pc") , { gcc_eip , dwarf_eip , LLDB_REGNUM_GENERIC_PC , 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 }},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fcw }},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fsw }},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ftw }},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fop }},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ip }},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_cs }},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_dp }},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ds }},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_mxcsr }},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }},
+ { 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 }},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }}
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+void
+RegisterContextMach_i386::Invalidate ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextMach_i386::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextMach_i386::GetRegisterInfoAtIndex (uint32_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextMach_i386::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextMach_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
+RegisterContextMach_i386::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextMach_i386::GetRegisterSet (uint32_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
+RegisterContextMach_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
+RegisterContextMach_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]);
+ }
+ }
+}
+
+
+
+kern_return_t
+RegisterContextMach_i386::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = GPRWordCount;
+ SetError(set, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&gpr, &count));
+ LogGPR (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_THREAD), "RegisterContextMach_i386::ReadGPR()");
+ }
+ return GetError(set, Read);
+}
+
+kern_return_t
+RegisterContextMach_i386::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = FPUWordCount;
+ SetError(set, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&fpu, &count));
+ }
+ return GetError(set, Read);
+}
+
+kern_return_t
+RegisterContextMach_i386::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = EXCWordCount;
+ SetError(set, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&exc, &count));
+ }
+ return GetError(set, Read);
+}
+
+kern_return_t
+RegisterContextMach_i386::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&gpr, GPRWordCount));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+kern_return_t
+RegisterContextMach_i386::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&fpu, FPUWordCount));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+kern_return_t
+RegisterContextMach_i386::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&exc, EXCWordCount));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+kern_return_t
+RegisterContextMach_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 KERN_INVALID_ARGUMENT;
+}
+
+kern_return_t
+RegisterContextMach_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 KERN_INVALID_ARGUMENT;
+}
+
+bool
+RegisterContextMach_i386::ReadRegisterValue (uint32_t reg, Scalar &value)
+{
+ int set = RegisterContextMach_i386::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ 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
+RegisterContextMach_i386::WriteRegisterValue (uint32_t reg, const Scalar &value)
+{
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ 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.UInt(0);
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.UInt(0);
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.UInt(0);
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.UInt(0);
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.UInt(0);
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.UInt(0);
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.UInt(0);
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.UInt(0);
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.UInt(0);
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.UInt(0);
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.UInt(0);
+ 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, reg_value.value.vector.uint8, 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 (fpu.xmm[reg - fpu_xmm0].bytes, reg_value.value.vector.uint8, 16);
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.UInt(0);
+ break;
+
+ case exc_err:
+ exc.err = value.UInt(0);
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.UInt(0);
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextMach_i386::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
+{
+ int set = RegisterContextMach_i386::GetSetForNativeRegNum (reg);
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ 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:
+ data.SetData(&gpr.eax + reg - gpr_eax, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fcw:
+ data.SetData(&fpu.fcw, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fsw:
+ data.SetData(&fpu.fsw, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_ftw:
+ data.SetData(&fpu.ftw, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fop:
+ data.SetData(&fpu.fop, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_ip:
+ data.SetData(&fpu.ip, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_cs:
+ data.SetData(&fpu.cs, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_dp:
+ data.SetData(&fpu.dp, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_ds:
+ data.SetData(&fpu.ds, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_mxcsr:
+ data.SetData(&fpu.mxcsr, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_mxcsrmask:
+ data.SetData(&fpu.mxcsrmask, reg_info->byte_size, eByteOrderHost);
+ 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:
+ data.SetData(fpu.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, eByteOrderHost);
+ 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:
+ data.SetData(fpu.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_trapno:
+ data.SetData(&exc.trapno, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_err:
+ data.SetData(&exc.err, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_faultvaddr:
+ data.SetData(&exc.faultvaddr, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool
+RegisterContextMach_i386::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
+{
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL && data.ValidOffsetForDataOfSize(data_offset, reg_info->byte_size))
+ return false;
+
+ uint32_t offset = data_offset;
+ 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] = data.GetU32 (&offset);
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = data.GetU16(&offset);
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = data.GetU16(&offset);
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = data.GetU8(&offset);
+ break;
+
+ case fpu_fop:
+ fpu.fop = data.GetU16(&offset);
+ break;
+
+ case fpu_ip:
+ fpu.ip = data.GetU32(&offset);
+ break;
+
+ case fpu_cs:
+ fpu.cs = data.GetU16(&offset);
+ break;
+
+ case fpu_dp:
+ fpu.dp = data.GetU32(&offset);
+ break;
+
+ case fpu_ds:
+ fpu.ds = data.GetU16(&offset);
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = data.GetU32(&offset);
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = data.GetU32(&offset);
+ 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, data.PeekData(offset, reg_info->byte_size), reg_info->byte_size);
+ 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, data.PeekData(offset, reg_info->byte_size), reg_info->byte_size);
+ return false;
+
+ case exc_trapno:
+ exc.trapno = data.GetU32 (&offset);
+ break;
+
+ case exc_err:
+ exc.err = data.GetU32 (&offset);
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = data.GetU32 (&offset);
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextMach_i386::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
+RegisterContextMach_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() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteFPU() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteEXC() == KERN_SUCCESS)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextMach_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;
+ }
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+bool
+RegisterContextMach_i386::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(false) != KERN_SUCCESS)
+ 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() == KERN_SUCCESS;
+}
+
+
+
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.h b/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.h
new file mode 100644
index 00000000000..580186752a9
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_i386.h
@@ -0,0 +1,256 @@
+//===-- 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 "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextMach_i386 : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextMach_i386(lldb_private::Thread &thread,
+ lldb_private::StackFrame *frame);
+
+ virtual
+ ~RegisterContextMach_i386();
+
+ virtual void
+ Invalidate ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb::RegisterSet *
+ GetRegisterSet (uint32_t set);
+
+ virtual bool
+ ReadRegisterValue (uint32_t reg, lldb_private::Scalar &value);
+
+ virtual bool
+ ReadRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegisterValue (uint32_t reg, const lldb_private::Scalar &value);
+
+ virtual bool
+ WriteRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data, uint32_t data_offset = 0);
+
+ 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;
+ kern_return_t gpr_errs[2]; // Read/Write errors
+ kern_return_t fpu_errs[2]; // Read/Write errors
+ kern_return_t exc_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ kern_return_t
+ 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, kern_return_t 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) == KERN_SUCCESS;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *title);
+
+ kern_return_t
+ ReadGPR (bool force);
+
+ kern_return_t
+ ReadFPU (bool force);
+
+ kern_return_t
+ ReadEXC (bool force);
+
+ kern_return_t
+ WriteGPR ();
+
+ kern_return_t
+ WriteFPU ();
+
+ kern_return_t
+ WriteEXC ();
+
+ kern_return_t
+ ReadRegisterSet (uint32_t set, bool force);
+
+ kern_return_t
+ 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::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextMach_i386_h_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.cpp
new file mode 100644
index 00000000000..a7ed32e649a
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.cpp
@@ -0,0 +1,1328 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+#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/Scalar.h"
+
+// Project includes
+#include "RegisterContextMach_x86_64.h"
+#include "ProcessMacOSXLog.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,
+};
+
+RegisterContextMach_x86_64::RegisterContextMach_x86_64 (Thread &thread, StackFrame *frame) :
+ RegisterContext (thread, frame),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextMach_x86_64::~RegisterContextMach_x86_64()
+{
+}
+
+#define GPR_OFFSET(reg) (offsetof (RegisterContextMach_x86_64::GPR, reg))
+#define FPU_OFFSET(reg) (offsetof (RegisterContextMach_x86_64::FPU, reg) + sizeof (RegisterContextMach_x86_64::GPR))
+#define EXC_OFFSET(reg) (offsetof (RegisterContextMach_x86_64::EXC, reg) + sizeof (RegisterContextMach_x86_64::GPR) + sizeof (RegisterContextMach_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(((RegisterContextMach_x86_64::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex, gpr_##reg
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextMach_x86_64::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex, fpu_##reg
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextMach_x86_64::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, fpu_##reg##i, { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, LLDB_INVALID_REGNUM, gdb_fpu_##reg##i }
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextMach_x86_64::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex, exc_##reg
+
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextMach_x86_64::GPR) + sizeof (RegisterContextMach_x86_64::FPU) + sizeof (RegisterContextMach_x86_64::EXC))
+
+// General purpose registers for 64 bit
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC REG KIND NUM DWARF REG KIND NUM GENERIC REG KIND NUM GDB REG KIND NUM
+// =============================== ======================= =================== ========================== ==========================
+ { 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_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_fcw }},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_fsw }},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_ftw }},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_fop }},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_ip }},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_cs }},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_dp }},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_ds }},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fpu_mxcsr }},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }},
+ { 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 }},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM }}
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+
+void
+RegisterContextMach_x86_64::Invalidate ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextMach_x86_64::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+
+const RegisterInfo *
+RegisterContextMach_x86_64::GetRegisterInfoAtIndex (uint32_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+
+size_t
+RegisterContextMach_x86_64::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextMach_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
+RegisterContextMach_x86_64::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextMach_x86_64::GetRegisterSet (uint32_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+int
+RegisterContextMach_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
+RegisterContextMach_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.16llx", g_register_infos[reg].name, (&gpr.rax)[reg]);
+ }
+ }
+}
+
+kern_return_t
+RegisterContextMach_x86_64::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = GPRWordCount;
+ SetError(GPRRegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&gpr, &count));
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_THREAD);
+ if (log)
+ LogGPR (log, "RegisterContextMach_x86_64::ReadGPR(thread = 0x%4.4x)", GetThreadID());
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_x86_64::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = FPUWordCount;
+ SetError(FPURegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&fpu, &count));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_x86_64::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ mach_msg_type_number_t count = EXCWordCount;
+ SetError(EXCRegSet, Read, ::thread_get_state(GetThreadID(), set, (thread_state_t)&exc, &count));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+kern_return_t
+RegisterContextMach_x86_64::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_THREAD);
+ if (log)
+ LogGPR (log, "RegisterContextMach_x86_64::WriteGPR (thread = 0x%4.4x)", GetThreadID());
+ SetError (set, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&gpr, GPRWordCount));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+kern_return_t
+RegisterContextMach_x86_64::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&fpu, FPUWordCount));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+kern_return_t
+RegisterContextMach_x86_64::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, ::thread_set_state(GetThreadID(), set, (thread_state_t)&exc, EXCWordCount));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+kern_return_t
+RegisterContextMach_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 KERN_INVALID_ARGUMENT;
+}
+
+kern_return_t
+RegisterContextMach_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 KERN_INVALID_ARGUMENT;
+}
+
+
+bool
+RegisterContextMach_x86_64::ReadRegisterValue (uint32_t reg, Scalar &value)
+{
+ int set = RegisterContextMach_x86_64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ 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:
+ // 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:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ // 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
+RegisterContextMach_x86_64::WriteRegisterValue (uint32_t reg, const Scalar &value)
+{
+ int set = RegisterContextMach_x86_64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ 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.ULongLong(0);
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.UInt(0);
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.UInt(0);
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.UInt(0);
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.UInt(0);
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.UInt(0);
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.UInt(0);
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.UInt(0);
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.UInt(0);
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.UInt(0);
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.UInt(0);
+ 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, reg_value.value.vector.uint8, 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:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ //::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, reg_value.value.vector.uint8, 16);
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.UInt(0);
+ break;
+
+ case exc_err:
+ exc.err = value.UInt(0);
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.UInt(0);
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextMach_x86_64::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
+{
+ int set = RegisterContextMach_x86_64::GetSetForNativeRegNum (reg);
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ 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:
+ data.SetData(&gpr.rax + reg - gpr_rax, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fcw:
+ data.SetData(&fpu.fcw, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fsw:
+ data.SetData(&fpu.fsw, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_ftw:
+ data.SetData(&fpu.ftw, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_fop:
+ data.SetData(&fpu.fop, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_ip:
+ data.SetData(&fpu.ip, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_cs:
+ data.SetData(&fpu.cs, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_dp:
+ data.SetData(&fpu.dp, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_ds:
+ data.SetData(&fpu.ds, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_mxcsr:
+ data.SetData(&fpu.mxcsr, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case fpu_mxcsrmask:
+ data.SetData(&fpu.mxcsrmask, reg_info->byte_size, eByteOrderHost);
+ 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:
+ data.SetData(fpu.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, eByteOrderHost);
+ 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:
+ data.SetData(fpu.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_trapno:
+ data.SetData(&exc.trapno, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_err:
+ data.SetData(&exc.err, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ case exc_faultvaddr:
+ data.SetData(&exc.faultvaddr, reg_info->byte_size, eByteOrderHost);
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool
+RegisterContextMach_x86_64::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
+{
+ int set = RegisterContextMach_x86_64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL && data.ValidOffsetForDataOfSize(data_offset, reg_info->byte_size))
+ return false;
+
+ uint32_t offset = data_offset;
+ 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] = data.GetU32 (&offset);
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = data.GetU16(&offset);
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = data.GetU16(&offset);
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = data.GetU8(&offset);
+ break;
+
+ case fpu_fop:
+ fpu.fop = data.GetU16(&offset);
+ break;
+
+ case fpu_ip:
+ fpu.ip = data.GetU32(&offset);
+ break;
+
+ case fpu_cs:
+ fpu.cs = data.GetU16(&offset);
+ break;
+
+ case fpu_dp:
+ fpu.dp = data.GetU32(&offset);
+ break;
+
+ case fpu_ds:
+ fpu.ds = data.GetU16(&offset);
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = data.GetU32(&offset);
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = data.GetU32(&offset);
+ 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, data.PeekData(offset, reg_info->byte_size), reg_info->byte_size);
+ 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:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ ::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, data.PeekData(offset, reg_info->byte_size), reg_info->byte_size);
+ return false;
+
+ case exc_trapno:
+ exc.trapno = data.GetU32 (&offset);
+ break;
+
+ case exc_err:
+ exc.err = data.GetU32 (&offset);
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = data.GetU32 (&offset);
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextMach_x86_64::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
+RegisterContextMach_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() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteFPU() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteEXC() == KERN_SUCCESS)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextMach_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;
+ }
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+bool
+RegisterContextMach_x86_64::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(true) != KERN_SUCCESS)
+ 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() == KERN_SUCCESS;
+}
+
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.h b/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.h
new file mode 100644
index 00000000000..4f33bbdc2db
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.h
@@ -0,0 +1,261 @@
+//===-- 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 "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextMach_x86_64 : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextMach_x86_64 (lldb_private::Thread &thread,
+ lldb_private::StackFrame *frame);
+
+ virtual
+ ~RegisterContextMach_x86_64();
+
+ virtual void
+ Invalidate ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb::RegisterSet *
+ GetRegisterSet (uint32_t set);
+
+ virtual bool
+ ReadRegisterValue (uint32_t reg, lldb_private::Scalar &value);
+
+ virtual bool
+ ReadRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegisterValue (uint32_t reg, const lldb_private::Scalar &value);
+
+ virtual bool
+ WriteRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data, uint32_t data_offset = 0);
+
+ 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:
+
+ typedef 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;
+ kern_return_t gpr_errs[2]; // Read/Write errors
+ kern_return_t fpu_errs[2]; // Read/Write errors
+ kern_return_t exc_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ kern_return_t
+ 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, kern_return_t 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) == KERN_SUCCESS;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *format, ...);
+
+ kern_return_t
+ ReadGPR (bool force);
+
+ kern_return_t
+ ReadFPU (bool force);
+
+ kern_return_t
+ ReadEXC (bool force);
+
+ kern_return_t
+ WriteGPR ();
+
+ kern_return_t
+ WriteFPU ();
+
+ kern_return_t
+ WriteEXC ();
+
+ kern_return_t
+ ReadRegisterSet (uint32_t set, bool force);
+
+ kern_return_t
+ 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::RegisterInfo *
+ GetRegisterInfos ();
+
+};
+
+#endif // liblldb_RegisterContextMach_x86_64_h_
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp
new file mode 100644
index 00000000000..46d84a853d0
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp
@@ -0,0 +1,769 @@
+//===-- ThreadMacOSX.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ThreadMacOSX.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "ProcessMacOSX.h"
+#include "ProcessMacOSXLog.h"
+#include "MachThreadContext.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Breakpoint/WatchpointLocation.h"
+#include "lldb/Core/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Thread Registers
+//----------------------------------------------------------------------
+
+ThreadMacOSX::ThreadMacOSX (ProcessMacOSX &process, lldb::tid_t tid) :
+ Thread(process, tid),
+ m_fp_pc_pairs(),
+ m_basic_info(),
+ m_suspend_count(0),
+ m_stop_exception(),
+ m_context()
+{
+ ProcessMacOSX::CreateArchCalback create_arch_callback = process.GetArchCreateCallback();
+ assert(create_arch_callback != NULL);
+ m_context.reset(create_arch_callback(process.GetArchSpec(), *this));
+ assert(m_context.get() != NULL);
+ m_context->InitializeInstance();
+ ::bzero (&m_basic_info, sizeof (m_basic_info));
+ ::bzero (&m_ident_info, sizeof (m_ident_info));
+ ::bzero (&m_proc_threadinfo, sizeof (m_proc_threadinfo));
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD | PD_LOG_VERBOSE, "ThreadMacOSX::ThreadMacOSX ( pid = %i, tid = 0x%4.4x, )", m_process.GetID(), GetID());
+}
+
+ThreadMacOSX::~ThreadMacOSX ()
+{
+}
+
+#if defined (__i386__) || defined (__x86_64__)
+ #define MACH_SOFTWARE_BREAKPOINT_DATA_0 EXC_I386_BPT
+ #define MACH_TRAP_DATA_0 EXC_I386_SGL
+#elif defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
+ #define MACH_SOFTWARE_BREAKPOINT_DATA_0 EXC_PPC_BREAKPOINT
+
+#elif defined (__arm__)
+ #define MACH_SOFTWARE_BREAKPOINT_DATA_0 EXC_ARM_BREAKPOINT
+#endif
+
+
+bool
+ThreadMacOSX::GetRawStopReason (Thread::StopInfo *stop_info )
+{
+ stop_info->SetThread(this);
+
+ bool success = GetStopException().GetStopInfo(stop_info);
+
+
+#if defined (MACH_SOFTWARE_BREAKPOINT_DATA_0) || defined (MACH_TRAP_DATA_0)
+ if (stop_info->GetStopReason() == eStopReasonException)
+ {
+ if (stop_info->GetExceptionType() == EXC_BREAKPOINT && stop_info->GetExceptionDataCount() == 2)
+ {
+ const lldb::addr_t data_0 = stop_info->GetExceptionDataAtIndex(0);
+#if defined (MACH_SOFTWARE_BREAKPOINT_DATA_0)
+ if (data_0 == MACH_SOFTWARE_BREAKPOINT_DATA_0)
+ {
+ lldb::addr_t pc = GetRegisterContext()->GetPC();
+ lldb::user_id_t break_id = m_process.GetBreakpointSiteList().FindIDByAddress(pc);
+ if (break_id != LLDB_INVALID_BREAK_ID)
+ {
+ stop_info->Clear ();
+ stop_info->SetStopReasonWithBreakpointSiteID (break_id);
+ return success;
+ }
+ }
+#endif
+#if defined (MACH_TRAP_DATA_0)
+ if (data_0 == MACH_TRAP_DATA_0)
+ {
+ stop_info->Clear ();
+ stop_info->SetStopReasonToTrace ();
+ return success;
+ }
+#endif
+ }
+ }
+#endif
+
+ if (stop_info->GetStopReason() == eStopReasonException)
+ {
+ if (stop_info->GetExceptionType() == EXC_SOFTWARE &&
+ stop_info->GetExceptionDataCount() == 2 &&
+ stop_info->GetExceptionDataAtIndex(0) == EXC_SOFT_SIGNAL)
+ {
+ int signo = stop_info->GetExceptionDataAtIndex(1);
+ stop_info->Clear ();
+ stop_info->SetStopReasonWithSignal (signo);
+ }
+ }
+ else
+ {
+ stop_info->SetStopReasonToNone();
+ }
+
+ return success;
+}
+
+const char *
+ThreadMacOSX::GetInfo ()
+{
+ return GetBasicInfoAsString();
+}
+
+bool
+ThreadMacOSX::GetIdentifierInfo ()
+{
+#ifdef THREAD_IDENTIFIER_INFO_COUNT
+ if (m_ident_info.thread_id == 0)
+ {
+ mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
+ return ::thread_info (GetID(), THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count) == KERN_SUCCESS;
+ }
+#else
+ //m_error.SetErrorString("Thread_info doesn't support THREAD_IDENTIFIER_INFO.");
+#endif
+
+ return false;
+}
+
+const char *
+ThreadMacOSX::GetDispatchQueueName()
+{
+ if (GetIdentifierInfo ())
+ {
+ if (m_ident_info.dispatch_qaddr == 0)
+ return NULL;
+
+ uint8_t memory_buffer[8];
+ DataExtractor data(memory_buffer, sizeof(memory_buffer), m_process.GetByteOrder(), m_process.GetAddressByteSize());
+ ModuleSP module_sp(m_process.GetTarget().GetImages().FindFirstModuleForFileSpec (FileSpec("libSystem.B.dylib")));
+ if (module_sp.get() == NULL)
+ return NULL;
+
+ lldb::addr_t dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS;
+ const Symbol *dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (ConstString("dispatch_queue_offsets"), eSymbolTypeData);
+ if (dispatch_queue_offsets_symbol)
+ dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetValue().GetLoadAddress(&GetProcess());
+
+ if (dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
+ return NULL;
+
+ // Excerpt from src/queue_private.h
+ struct dispatch_queue_offsets_s
+ {
+ uint16_t dqo_version;
+ uint16_t dqo_label;
+ uint16_t dqo_label_size;
+ } dispatch_queue_offsets;
+
+ Error error;
+ if (m_process.ReadMemory (dispatch_queue_offsets_addr, memory_buffer, sizeof(dispatch_queue_offsets), error) == sizeof(dispatch_queue_offsets))
+ {
+ uint32_t data_offset = 0;
+ if (data.GetU16(&data_offset, &dispatch_queue_offsets.dqo_version, sizeof(dispatch_queue_offsets)/sizeof(uint16_t)))
+ {
+ if (m_process.ReadMemory (m_ident_info.dispatch_qaddr, &memory_buffer, data.GetAddressByteSize(), error) == data.GetAddressByteSize())
+ {
+ data_offset = 0;
+ lldb::addr_t queue_addr = data.GetAddress(&data_offset);
+ lldb::addr_t label_addr = queue_addr + dispatch_queue_offsets.dqo_label;
+ const size_t chunk_size = 32;
+ uint32_t label_pos = 0;
+ m_dispatch_queue_name.resize(chunk_size, '\0');
+ while (1)
+ {
+ size_t bytes_read = m_process.ReadMemory (label_addr + label_pos, &m_dispatch_queue_name[label_pos], chunk_size, error);
+
+ if (bytes_read <= 0)
+ break;
+
+ if (m_dispatch_queue_name.find('\0', label_pos) != std::string::npos)
+ break;
+ label_pos += bytes_read;
+ }
+ m_dispatch_queue_name.erase(m_dispatch_queue_name.find('\0'));
+ }
+ }
+ }
+ }
+
+ if (m_dispatch_queue_name.empty())
+ return NULL;
+ return m_dispatch_queue_name.c_str();
+}
+
+const char *
+ThreadMacOSX::GetName ()
+{
+ if (GetIdentifierInfo ())
+ ::proc_pidinfo (m_process.GetID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo));
+
+ // No thread name, lets return the queue name instead
+ if (m_proc_threadinfo.pth_name[0] == '\0')
+ return GetDispatchQueueName();
+
+ // Return the thread name if there was one
+ if (m_proc_threadinfo.pth_name[0])
+ return m_proc_threadinfo.pth_name;
+ return NULL;
+}
+
+bool
+ThreadMacOSX::WillResume (StateType resume_state)
+{
+ ThreadWillResume(resume_state);
+ Thread::WillResume(resume_state);
+ return true;
+}
+
+void
+ThreadMacOSX::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context
+ GetRegisterContext()->Invalidate();
+
+ m_context->RefreshStateAfterStop();
+
+ // We may have suspended this thread so the primary thread could step
+ // without worrying about race conditions, so lets restore our suspend
+ // count.
+ RestoreSuspendCount();
+
+ // Update the basic information for a thread for suspend count reasons.
+ ThreadMacOSX::GetBasicInfo(GetID(), &m_basic_info);
+ m_suspend_count = m_basic_info.suspend_count;
+ m_basic_info_string.clear();
+}
+
+uint32_t
+ThreadMacOSX::GetStackFrameCount()
+{
+ if (m_fp_pc_pairs.empty())
+ GetStackFrameData(m_fp_pc_pairs);
+ return m_fp_pc_pairs.size();
+}
+
+// Make sure that GetStackFrameAtIndex() does NOT call GetStackFrameCount() when
+// getting the stack frame at index zero! This way GetStackFrameCount() (via
+// GetStackFRameData()) can call this function to get the first frame in order
+// to provide the first frame to a lower call for efficiency sake (avoid
+// redundant lookups in the frame symbol context).
+lldb::StackFrameSP
+ThreadMacOSX::GetStackFrameAtIndex (uint32_t idx)
+{
+ StackFrameSP frame_sp(m_frames.GetFrameAtIndex(idx));
+
+ if (frame_sp)
+ return frame_sp;
+
+ // Don't try and fetch a frame while process is running
+ // Calling IsRunning isn't right here, because IsRunning reads the Public
+ // state but we need to be able to read the stack frames in the ShouldStop
+ // methods, which happen before the Public state has been updated.
+// if (m_process.IsRunning())
+// return frame_sp;
+
+ // Special case the first frame (idx == 0) so that we don't need to
+ // know how many stack frames there are to get it. If we need any other
+ // frames, then we do need to know if "idx" is a valid index.
+ if (idx == 0)
+ {
+ // If this is the first frame, we want to share the thread register
+ // context with the stack frame at index zero.
+ GetRegisterContext();
+ assert (m_reg_context_sp.get());
+ frame_sp.reset (new StackFrame (idx, *this, m_reg_context_sp, m_reg_context_sp->GetFP(), m_reg_context_sp->GetPC()));
+ }
+ else if (idx < GetStackFrameCount())
+ {
+ assert (idx < m_fp_pc_pairs.size());
+ frame_sp.reset (new StackFrame (idx, *this, m_fp_pc_pairs[idx].first, m_fp_pc_pairs[idx].second));
+ }
+ m_frames.SetFrameAtIndex(idx, frame_sp);
+ return frame_sp;
+}
+
+void
+ThreadMacOSX::ClearStackFrames ()
+{
+ m_fp_pc_pairs.clear();
+ Thread::ClearStackFrames();
+}
+
+
+
+int32_t
+ThreadMacOSX::Suspend()
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ThreadMacOSX::%s ( )", __FUNCTION__);
+ lldb::tid_t tid = GetID ();
+ if (ThreadIDIsValid(tid))
+ {
+ Error err(::thread_suspend (tid), eErrorTypeMachKernel);
+ if (err.Success())
+ m_suspend_count++;
+ if (log || err.Fail())
+ err.PutToLog(log, "::thread_suspend (%4.4x)", tid);
+ }
+ return GetSuspendCount();
+}
+
+int32_t
+ThreadMacOSX::Resume()
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ThreadMacOSX::%s ()", __FUNCTION__);
+ lldb::tid_t tid = GetID ();
+ if (ThreadIDIsValid(tid))
+ {
+ while (m_suspend_count > 0)
+ {
+ Error err(::thread_resume (tid), eErrorTypeMachKernel);
+ if (err.Success())
+ m_suspend_count--;
+ if (log || err.Fail())
+ err.PutToLog(log, "::thread_resume (%4.4x)", tid);
+ }
+ }
+ return GetSuspendCount();
+}
+
+bool
+ThreadMacOSX::RestoreSuspendCount()
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ThreadMacOSX::%s ( )", __FUNCTION__);
+ Error err;
+ lldb::tid_t tid = GetID ();
+ if (ThreadIDIsValid(tid) == false)
+ return false;
+ else if (m_suspend_count > m_basic_info.suspend_count)
+ {
+ while (m_suspend_count > m_basic_info.suspend_count)
+ {
+ err = ::thread_resume (tid);
+ if (err.Success())
+ --m_suspend_count;
+ if (log || err.Fail())
+ err.PutToLog(log, "::thread_resume (%4.4x)", tid);
+ }
+ }
+ else if (m_suspend_count < m_basic_info.suspend_count)
+ {
+ while (m_suspend_count < m_basic_info.suspend_count)
+ {
+ err = ::thread_suspend (tid);
+ if (err.Success())
+ --m_suspend_count;
+ if (log || err.Fail())
+ err.PutToLog(log, "::thread_suspend (%4.4x)", tid);
+ }
+ }
+ return m_suspend_count == m_basic_info.suspend_count;
+}
+
+
+const char *
+ThreadMacOSX::GetBasicInfoAsString ()
+{
+ if (m_basic_info_string.empty())
+ {
+ StreamString sstr;
+ struct thread_basic_info basicInfo;
+
+ lldb::tid_t tid = GetID ();
+ if (GetBasicInfo(tid, &basicInfo))
+ {
+// char run_state_str[32];
+// size_t run_state_str_size = sizeof(run_state_str);
+// switch (basicInfo.run_state)
+// {
+// case TH_STATE_RUNNING: strncpy(run_state_str, "running", run_state_str_size); break;
+// case TH_STATE_STOPPED: strncpy(run_state_str, "stopped", run_state_str_size); break;
+// case TH_STATE_WAITING: strncpy(run_state_str, "waiting", run_state_str_size); break;
+// case TH_STATE_UNINTERRUPTIBLE: strncpy(run_state_str, "uninterruptible", run_state_str_size); break;
+// case TH_STATE_HALTED: strncpy(run_state_str, "halted", run_state_str_size); break;
+// default: snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break; // ???
+// }
+ float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
+ float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
+ sstr.Printf("Thread 0x%4.4x: user=%f system=%f cpu=%d sleep_time=%d",
+ InferiorThreadID(),
+ user,
+ system,
+ basicInfo.cpu_usage,
+ basicInfo.sleep_time);
+ m_basic_info_string.assign (sstr.GetData(), sstr.GetSize());
+ }
+ }
+ if (m_basic_info_string.empty())
+ return NULL;
+ return m_basic_info_string.c_str();
+}
+
+
+//const uint8_t *
+//ThreadMacOSX::SoftwareBreakpointOpcode (size_t break_op_size) const
+//{
+// return m_context->SoftwareBreakpointOpcode(break_op_size);
+//}
+
+
+lldb::tid_t
+ThreadMacOSX::InferiorThreadID() const
+{
+ mach_msg_type_number_t i;
+ mach_port_name_array_t names;
+ mach_port_type_array_t types;
+ mach_msg_type_number_t ncount, tcount;
+ lldb::tid_t inferior_tid = LLDB_INVALID_THREAD_ID;
+ task_t my_task = ::mach_task_self();
+ task_t task = GetMacOSXProcess().Task().GetTaskPort();
+
+ kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount);
+ if (kret == KERN_SUCCESS)
+ {
+ lldb::tid_t tid = GetID ();
+
+ for (i = 0; i < ncount; i++)
+ {
+ mach_port_t my_name;
+ mach_msg_type_name_t my_type;
+
+ kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type);
+ if (kret == KERN_SUCCESS)
+ {
+ ::mach_port_deallocate (my_task, my_name);
+ if (my_name == tid)
+ {
+ inferior_tid = names[i];
+ break;
+ }
+ }
+ }
+ // Free up the names and types
+ ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t));
+ ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t));
+ }
+ return inferior_tid;
+}
+
+bool
+ThreadMacOSX::GetBasicInfo(lldb::tid_t thread, struct thread_basic_info *basicInfoPtr)
+{
+ if (ThreadIDIsValid(thread))
+ {
+ unsigned int info_count = THREAD_BASIC_INFO_COUNT;
+ kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count);
+ if (err == KERN_SUCCESS)
+ return true;
+ }
+ ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info));
+ return false;
+}
+
+
+bool
+ThreadMacOSX::ThreadIDIsValid (lldb::tid_t thread)
+{
+ return thread != 0;
+}
+
+void
+ThreadMacOSX::Dump(Log *log, uint32_t index)
+{
+ const char * thread_run_state = NULL;
+
+ switch (m_basic_info.run_state)
+ {
+ case TH_STATE_RUNNING: thread_run_state = "running"; break; // 1 thread is running normally
+ case TH_STATE_STOPPED: thread_run_state = "stopped"; break; // 2 thread is stopped
+ case TH_STATE_WAITING: thread_run_state = "waiting"; break; // 3 thread is waiting normally
+ case TH_STATE_UNINTERRUPTIBLE: thread_run_state = "uninter"; break; // 4 thread is in an uninterruptible wait
+ case TH_STATE_HALTED: thread_run_state = "halted "; break; // 5 thread is halted at a
+ default: thread_run_state = "???"; break;
+ }
+
+ RegisterContext *reg_context = GetRegisterContext();
+ log->Printf ("thread[%u] %4.4x (%u): pc: 0x%8.8llx sp: 0x%8.8llx breakID: %d user: %d.%06.6d system: %d.%06.6d cpu: %d policy: %d run_state: %d (%s) flags: %d suspend_count: %d (current %d) sleep_time: %d",
+ index,
+ GetID (),
+ reg_context->GetPC (LLDB_INVALID_ADDRESS),
+ reg_context->GetSP (LLDB_INVALID_ADDRESS),
+ m_basic_info.user_time.seconds, m_basic_info.user_time.microseconds,
+ m_basic_info.system_time.seconds, m_basic_info.system_time.microseconds,
+ m_basic_info.cpu_usage,
+ m_basic_info.policy,
+ m_basic_info.run_state,
+ thread_run_state,
+ m_basic_info.flags,
+ m_basic_info.suspend_count, m_suspend_count,
+ m_basic_info.sleep_time);
+ //DumpRegisterState(0);
+}
+
+void
+ThreadMacOSX::ThreadWillResume (StateType resume_state)
+{
+ // Update the thread state to be the state we wanted when the task resumes
+ SetState (resume_state);
+ switch (resume_state)
+ {
+ case eStateSuspended:
+ Suspend();
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ Resume();
+ break;
+ }
+ m_context->ThreadWillResume();
+}
+
+void
+ThreadMacOSX::DidResume ()
+{
+ // TODO: cache current stack frames for next time in case we can match things up??
+ ClearStackFrames();
+ m_stop_exception.Clear();
+ Thread::DidResume();
+}
+
+bool
+ThreadMacOSX::ShouldStop(bool &step_more)
+{
+// TODO: REmove this after all is working, Process should be managing this
+// for us.
+//
+// // See if this thread is at a breakpoint?
+// lldb::user_id_t breakID = CurrentBreakpoint();
+//
+// if (LLDB_BREAK_ID_IS_VALID(breakID))
+// {
+// // This thread is sitting at a breakpoint, ask the breakpoint
+// // if we should be stopping here.
+// if (Process()->Breakpoints().ShouldStop(ProcessID(), ThreadID(), breakID))
+// return true;
+// else
+// {
+// // The breakpoint said we shouldn't stop, but we may have gotten
+// // a signal or the user may have requested to stop in some other
+// // way. Stop if we have a valid exception (this thread won't if
+// // another thread was the reason this process stopped) and that
+// // exception, is NOT a breakpoint exception (a common case would
+// // be a SIGINT signal).
+// if (GetStopException().IsValid() && !GetStopException().IsBreakpoint())
+// return true;
+// }
+// }
+// else
+// {
+ if (m_context->StepNotComplete())
+ {
+ step_more = true;
+ return false;
+ }
+// // The thread state is used to let us know what the thread was
+// // trying to do. ThreadMacOSX::ThreadWillResume() will set the
+// // thread state to various values depending if the thread was
+// // the current thread and if it was to be single stepped, or
+// // resumed.
+// if (GetState() == eStateRunning)
+// {
+// // If our state is running, then we should continue as we are in
+// // the process of stepping over a breakpoint.
+// return false;
+// }
+// else
+// {
+// // Stop if we have any kind of valid exception for this
+// // thread.
+// if (GetStopException().IsValid())
+// return true;
+// }
+// }
+// return false;
+ return true;
+}
+
+bool
+ThreadMacOSX::NotifyException(MachException::Data& exc)
+{
+ if (m_stop_exception.IsValid())
+ {
+ // We may have more than one exception for a thread, but we need to
+ // only remember the one that we will say is the reason we stopped.
+ // We may have been single stepping and also gotten a signal exception,
+ // so just remember the most pertinent one.
+ if (m_stop_exception.IsBreakpoint())
+ m_stop_exception = exc;
+ }
+ else
+ {
+ m_stop_exception = exc;
+ }
+// bool handled =
+ m_context->NotifyException(exc);
+// if (!handled)
+// {
+// handled = true;
+// lldb::addr_t pc = GetPC();
+// lldb::user_id_t breakID = m_process.Breakpoints().FindIDCyAddress(pc);
+// SetCurrentBreakpoint(breakID);
+// switch (exc.exc_type)
+// {
+// case EXC_BAD_ACCESS:
+// break;
+// case EXC_BAD_INSTRUCTION:
+// break;
+// case EXC_ARITHMETIC:
+// break;
+// case EXC_EMULATION:
+// break;
+// case EXC_SOFTWARE:
+// break;
+// case EXC_BREAKPOINT:
+// break;
+// case EXC_SYSCALL:
+// break;
+// case EXC_MACH_SYSCALL:
+// break;
+// case EXC_RPC_ALERT:
+// break;
+// }
+// }
+// return handled;
+ return true;
+}
+
+RegisterContext *
+ThreadMacOSX::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL)
+ m_reg_context_sp.reset (CreateRegisterContextForFrame (NULL));
+ return m_reg_context_sp.get();
+}
+
+RegisterContext *
+ThreadMacOSX::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ return m_context->CreateRegisterContext (frame);
+}
+
+uint32_t
+ThreadMacOSX::SetHardwareBreakpoint (const BreakpointSite *bp)
+{
+ if (bp != NULL)
+ return GetRegisterContext()->SetHardwareBreakpoint(bp->GetLoadAddress(), bp->GetByteSize());
+ return LLDB_INVALID_INDEX32;
+}
+
+uint32_t
+ThreadMacOSX::SetHardwareWatchpoint (const WatchpointLocation *wp)
+{
+ if (wp != NULL)
+ return GetRegisterContext()->SetHardwareWatchpoint(wp->GetLoadAddress(), wp->GetByteSize(), wp->WatchpointRead(), wp->WatchpointWrite());
+ return LLDB_INVALID_INDEX32;
+}
+
+
+bool
+ThreadMacOSX::SaveFrameZeroState (RegisterCheckpoint &checkpoint)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ checkpoint.SetStackID(frame_sp->GetStackID());
+ return frame_sp->GetRegisterContext()->ReadAllRegisterValues (checkpoint.GetData());
+ }
+ return false;
+}
+
+bool
+ThreadMacOSX::RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ bool ret = frame_sp->GetRegisterContext()->WriteAllRegisterValues (checkpoint.GetData());
+
+ // Clear out all stack frames as our world just changed.
+ ClearStackFrames();
+ frame_sp->GetRegisterContext()->Invalidate();
+
+ return ret;
+ }
+ return false;
+}
+
+bool
+ThreadMacOSX::ClearHardwareBreakpoint (const BreakpointSite *bp)
+{
+ if (bp != NULL && bp->IsHardware())
+ return GetRegisterContext()->ClearHardwareBreakpoint(bp->GetHardwareIndex());
+ return false;
+}
+
+bool
+ThreadMacOSX::ClearHardwareWatchpoint (const WatchpointLocation *wp)
+{
+ if (wp != NULL && wp->IsHardware())
+ return GetRegisterContext()->ClearHardwareWatchpoint(wp->GetHardwareIndex());
+ return false;
+}
+
+size_t
+ThreadMacOSX::GetStackFrameData(std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ return m_context->GetStackFrameData(frame_sp.get(), fp_pc_pairs);
+}
+
+
+//void
+//ThreadMacOSX::NotifyBreakpointChanged (const BreakpointSite *bp)
+//{
+// if (bp)
+// {
+// lldb::user_id_t breakID = bp->GetID();
+// if (bp->IsEnabled())
+// {
+// if (bp->Address() == GetPC())
+// {
+// SetCurrentBreakpoint(breakID);
+// }
+// }
+// else
+// {
+// if (CurrentBreakpoint() == breakID)
+// {
+// SetCurrentBreakpoint(LLDB_INVALID_BREAK_ID);
+// }
+// }
+// }
+//}
+//
+
+
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.h b/lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.h
new file mode 100644
index 00000000000..0039f3639f1
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.h
@@ -0,0 +1,159 @@
+//===-- ThreadMacOSX.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ThreadMacOSX_h_
+#define liblldb_ThreadMacOSX_h_
+
+#include <libproc.h>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "MachException.h"
+
+class ProcessMacOSX;
+class MachThreadContext;
+
+class ThreadMacOSX : public lldb_private::Thread
+{
+public:
+ ThreadMacOSX (ProcessMacOSX &process, lldb::tid_t tid);
+
+ virtual
+ ~ThreadMacOSX ();
+
+ virtual bool
+ WillResume (lldb::StateType resume_state);
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual const char *
+ GetInfo ();
+
+ virtual const char *
+ GetName ();
+
+ virtual lldb_private::RegisterContext *
+ GetRegisterContext ();
+
+ virtual lldb_private::RegisterContext *
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ virtual bool
+ SaveFrameZeroState (RegisterCheckpoint &checkpoint);
+
+ virtual bool
+ RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint);
+
+ virtual uint32_t
+ GetStackFrameCount();
+
+ virtual lldb::StackFrameSP
+ GetStackFrameAtIndex (uint32_t idx);
+
+ virtual void
+ ClearStackFrames ();
+
+ ProcessMacOSX &
+ GetMacOSXProcess ()
+ {
+ return (ProcessMacOSX &)m_process;
+ }
+
+ const ProcessMacOSX &
+ GetMacOSXProcess () const
+ {
+ return (ProcessMacOSX &)m_process;
+ }
+
+ void
+ Dump (lldb_private::Log *log, uint32_t index);
+
+ lldb::tid_t
+ InferiorThreadID () const;
+
+ static bool
+ ThreadIDIsValid (lldb::tid_t thread);
+
+ int32_t
+ Resume ();
+
+ int32_t
+ Suspend ();
+
+ int32_t
+ GetSuspendCount () const { return m_suspend_count; }
+
+ bool
+ RestoreSuspendCount ();
+
+ uint32_t
+ SetHardwareBreakpoint (const lldb_private::BreakpointSite *bp);
+
+ uint32_t
+ SetHardwareWatchpoint (const lldb_private::WatchpointLocation *wp);
+
+ bool
+ ClearHardwareBreakpoint (const lldb_private::BreakpointSite *bp);
+
+ bool
+ ClearHardwareWatchpoint (const lldb_private::WatchpointLocation *wp);
+
+ void
+ ThreadWillResume (lldb::StateType resume_state);
+
+ virtual void
+ DidResume ();
+
+ bool
+ ShouldStop (bool &step_more);
+
+ bool
+ NotifyException (MachException::Data& exc);
+
+ const MachException::Data&
+ GetStopException () { return m_stop_exception; }
+
+ const char *
+ GetBasicInfoAsString ();
+
+ size_t
+ GetStackFrameData (std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs);
+
+ virtual bool
+ GetRawStopReason (lldb_private::Thread::StopInfo *stop_info);
+
+protected:
+ bool
+ GetIdentifierInfo ();
+
+ const char *
+ GetDispatchQueueName();
+
+ static bool
+ GetBasicInfo (lldb::tid_t threadID, struct thread_basic_info *basic_info);
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ std::vector<std::pair<lldb::addr_t, lldb::addr_t> > m_fp_pc_pairs;
+ struct thread_basic_info m_basic_info; // Basic information for a thread used to see if a thread is valid
+ std::string m_basic_info_string;// Basic thread info as a C string.
+#ifdef THREAD_IDENTIFIER_INFO_COUNT
+ thread_identifier_info_data_t m_ident_info;
+ struct proc_threadinfo m_proc_threadinfo;
+ std::string m_dispatch_queue_name;
+#endif
+ int32_t m_suspend_count; // The current suspend count
+ MachException::Data m_stop_exception; // The best exception that describes why this thread is stopped
+ std::auto_ptr<MachThreadContext> m_context; // The arch specific thread context for this thread (register state and more)
+
+};
+
+#endif // liblldb_ThreadMacOSX_h_
diff --git a/lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.cpp b/lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.cpp
new file mode 100644
index 00000000000..bf6b6c2eac4
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.cpp
@@ -0,0 +1,327 @@
+//===-- LibUnwindRegisterContext.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibUnwindRegisterContext.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/Thread.h"
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// LibUnwindRegisterContext constructor
+//----------------------------------------------------------------------
+LibUnwindRegisterContext::LibUnwindRegisterContext
+(
+ Thread &thread,
+ StackFrame *frame,
+ const lldb_private::unw_cursor_t& unwind_cursor
+) :
+ RegisterContext (thread, frame),
+ m_unwind_cursor (unwind_cursor),
+ m_unwind_cursor_is_valid (true)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+LibUnwindRegisterContext::~LibUnwindRegisterContext()
+{
+}
+
+void
+LibUnwindRegisterContext::Invalidate ()
+{
+ m_unwind_cursor_is_valid = false;
+}
+
+size_t
+LibUnwindRegisterContext::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const lldb::RegisterInfo *
+LibUnwindRegisterContext::GetRegisterInfoAtIndex (uint32_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg);
+}
+
+size_t
+LibUnwindRegisterContext::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount();
+}
+
+
+
+const lldb::RegisterSet *
+LibUnwindRegisterContext::GetRegisterSet (uint32_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+
+
+bool
+LibUnwindRegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value)
+{
+ if (m_unwind_cursor_is_valid == false)
+ return false;
+
+ // Read the register
+ unw_word_t reg_value;
+ if (unw_get_reg (&m_unwind_cursor, reg, &reg_value) != UNW_ESUCCESS)
+ return false;
+
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ switch (reg_info->encoding)
+ {
+ case eEncodingUint:
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ value = (uint32_t)reg_value;
+ return true;
+
+ case 8:
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case eEncodingSint:
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ value = (int32_t)reg_value;
+ return true;
+
+ case 8:
+ value = (int64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case eEncodingIEEE754:
+ if (reg_info->byte_size > sizeof(unw_word_t))
+ return false;
+
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ if (sizeof (float) == sizeof(uint32_t))
+ {
+ value = (uint32_t)reg_value;
+ return true;
+ }
+ else if (sizeof (float) == sizeof(uint64_t))
+ {
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case sizeof (double):
+ if (sizeof (double) == sizeof(uint32_t))
+ {
+ value = (uint32_t)reg_value;
+ return true;
+ }
+ else if (sizeof (double) == sizeof(uint64_t))
+ {
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case sizeof (long double):
+ if (sizeof (long double) == sizeof(uint32_t))
+ {
+ value = (uint32_t)reg_value;
+ return true;
+ }
+ else if (sizeof (long double) == sizeof(uint64_t))
+ {
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+ }
+ break;
+ }
+ return false;
+}
+
+
+bool
+LibUnwindRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
+{
+ Scalar reg_value;
+
+ if (ReadRegisterValue (reg, reg_value))
+ {
+ if (reg_value.GetData(data))
+ {
+ // "reg_value" is local and now "data" points to the data within
+ // "reg_value", so we must make a copy that will live within "data"
+ DataBufferSP data_sp (new DataBufferHeap (data.GetDataStart(), data.GetByteSize()));
+ data.SetData (data_sp, 0, data.GetByteSize());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+LibUnwindRegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value)
+{
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ return false;
+ unw_word_t reg_value;
+ switch (value.GetType())
+ {
+ case Scalar::e_sint: reg_value = value.SInt(); break;
+ case Scalar::e_uint: reg_value = value.UInt(); break;
+ case Scalar::e_slong: reg_value = value.SLong(); break;
+ case Scalar::e_ulong: reg_value = value.ULong(); break;
+ case Scalar::e_slonglong: reg_value = value.SLongLong(); break;
+ case Scalar::e_ulonglong: reg_value = value.ULongLong(); break;
+ case Scalar::e_float:
+ if (sizeof (float) == sizeof (unsigned int))
+ reg_value = value.UInt();
+ else if (sizeof (float) == sizeof (unsigned long))
+ reg_value = value.ULong();
+ else if (sizeof (float) == sizeof (unsigned long long))
+ reg_value = value.ULongLong();
+ else
+ return false;
+ break;
+
+ case Scalar::e_double:
+ if (sizeof (double) == sizeof (unsigned int))
+ reg_value = value.UInt();
+ else if (sizeof (double) == sizeof (unsigned long))
+ reg_value = value.ULong();
+ else if (sizeof (double) == sizeof (unsigned long long))
+ reg_value = value.ULongLong();
+ else
+ return false;
+ break;
+
+ case Scalar::e_long_double:
+ if (sizeof (long double) == sizeof (unsigned int))
+ reg_value = value.UInt();
+ else if (sizeof (long double) == sizeof (unsigned long))
+ reg_value = value.ULong();
+ else if (sizeof (long double) == sizeof (unsigned long long))
+ reg_value = value.ULongLong();
+ else
+ return false;
+ break;
+ }
+
+ return unw_set_reg (&m_unwind_cursor, reg, reg_value) == UNW_ESUCCESS;
+}
+
+
+bool
+LibUnwindRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
+{
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+
+ if (reg_info == NULL)
+ return false;
+ if (reg_info->byte_size > sizeof (unw_word_t))
+ return false;
+
+ Scalar value;
+ uint32_t offset = data_offset;
+
+ switch (reg_info->encoding)
+ {
+ case eEncodingUint:
+ if (reg_info->byte_size <= 4)
+ value = data.GetMaxU32 (&offset, reg_info->byte_size);
+ else if (reg_info->byte_size <= 8)
+ value = data.GetMaxU64 (&offset, reg_info->byte_size);
+ else
+ return false;
+ break;
+
+ case eEncodingSint:
+ if (reg_info->byte_size <= 4)
+ value = (int32_t)data.GetMaxU32 (&offset, reg_info->byte_size);
+ else if (reg_info->byte_size <= 8)
+ value = data.GetMaxS64 (&offset, reg_info->byte_size);
+ else
+ return false;
+ break;
+
+ case eEncodingIEEE754:
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ value = data.GetFloat (&offset);
+ break;
+
+ case sizeof (double):
+ value = data.GetDouble (&offset);
+ break;
+
+ case sizeof (long double):
+ value = data.GetLongDouble (&offset);
+ break;
+ default:
+ return false;
+ }
+ }
+ return WriteRegisterValue (reg, value);
+}
+
+
+bool
+LibUnwindRegisterContext::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
+LibUnwindRegisterContext::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
+LibUnwindRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
diff --git a/lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.h b/lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.h
new file mode 100644
index 00000000000..4e89b27961f
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/LibUnwindRegisterContext.h
@@ -0,0 +1,83 @@
+//===-- LibUnwindRegisterContext.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_LibUnwindRegisterContext_h_
+#define lldb_LibUnwindRegisterContext_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "libunwind.h"
+
+class LibUnwindRegisterContext : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ LibUnwindRegisterContext (lldb_private::Thread &thread,
+ lldb_private::StackFrame *frame,
+ const lldb_private::unw_cursor_t &unwind_cursor);
+
+ virtual
+ ~LibUnwindRegisterContext ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ Invalidate ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb::RegisterSet *
+ GetRegisterSet (uint32_t reg_set);
+
+ virtual bool
+ ReadRegisterValue (uint32_t reg, lldb_private::Scalar &value);
+
+ virtual bool
+ ReadRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegisterValue (uint32_t reg, const lldb_private::Scalar &value);
+
+ virtual bool
+ WriteRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data, uint32_t data_offset);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+private:
+ lldb_private::unw_cursor_t m_unwind_cursor;
+ bool m_unwind_cursor_is_valid;
+ //------------------------------------------------------------------
+ // For LibUnwindRegisterContext only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (LibUnwindRegisterContext);
+};
+
+#endif // lldb_LibUnwindRegisterContext_h_
diff --git a/lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.cpp b/lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.cpp
new file mode 100644
index 00000000000..58a7ac043c5
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.cpp
@@ -0,0 +1,306 @@
+//===-- MacOSXLibunwindCallbacks.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MacOSXLibunwindCallbacks_cpp_
+#define liblldb_MacOSXLibunwindCallbacks_cpp_
+#if defined(__cplusplus)
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "lldb-enumerations.h"
+#include "libunwind.h"
+#include "llvm-c/EnhancedDisassembly.h"
+
+using namespace lldb;
+
+namespace lldb_private {
+
+/* Don't implement (libunwind does not use)
+ find_proc_info
+ put_unwind_info
+ get_dyn_info_list_addr
+ access_mem
+ resume
+*/
+/*
+ Should implement (not needed yet)
+ access_fpreg
+ access_vecreg
+ proc_is_sigtramp
+ proc_is_inferior_function_call
+ access_reg_inf_func_call
+*/
+
+static int
+access_reg (lldb_private::unw_addr_space_t as, lldb_private::unw_regnum_t regnum, lldb_private::unw_word_t *valp, int write, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ /* FIXME Only support reading for now. */
+ if (write == 1)
+ return -1;
+ if (th->GetRegisterContext()->GetRegisterInfoAtIndex(regnum) == NULL)
+ return -1;
+ DataExtractor de;
+ if (!th->GetRegisterContext()->ReadRegisterBytes (regnum, de))
+ return -1;
+ memcpy (valp, de.GetDataStart(), de.GetByteSize());
+ return UNW_ESUCCESS;
+}
+
+static int
+get_proc_name (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t ip, char *bufp, size_t buf_len, lldb_private::unw_word_t *offp, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ Address addr;
+ if (!th->GetProcess().ResolveLoadAddress(ip, addr))
+ return -1;
+
+ SymbolContext sc;
+ if (!th->GetProcess().GetTarget().GetImages().ResolveSymbolContextForAddress (addr, eSymbolContextFunction, sc))
+ return -1;
+ if (!sc.symbol)
+ return -1;
+ strlcpy (bufp, sc.symbol->GetMangled().GetMangledName().AsCString(""), buf_len);
+ if (offp)
+ *offp = addr.GetLoadAddress(&th->GetProcess()) - sc.symbol->GetValue().GetLoadAddress(&th->GetProcess());
+ return UNW_ESUCCESS;
+}
+
+static int
+find_image_info (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t load_addr, lldb_private::unw_word_t *mh,
+ lldb_private::unw_word_t *text_start, lldb_private::unw_word_t *text_end,
+ lldb_private::unw_word_t *eh_frame, lldb_private::unw_word_t *eh_frame_len,
+ lldb_private::unw_word_t *compact_unwind_start, lldb_private::unw_word_t *compact_unwind_len, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ Address addr;
+ if (!th->GetProcess().ResolveLoadAddress(load_addr, addr))
+ return -1;
+
+ SymbolContext sc;
+ if (!th->GetProcess().GetTarget().GetImages().ResolveSymbolContextForAddress (addr, eSymbolContextModule, sc))
+ return -1;
+
+ SectionList *sl = sc.module_sp->GetObjectFile()->GetSectionList();
+ static ConstString g_segment_name_TEXT("__TEXT");
+ SectionSP text_segment_sp(sl->FindSectionByName(g_segment_name_TEXT));
+ if (!text_segment_sp)
+ return -1;
+
+ *mh = text_segment_sp->GetLoadBaseAddress (&th->GetProcess());
+ *text_start = text_segment_sp->GetLoadBaseAddress (&th->GetProcess());
+ *text_end = *text_start + text_segment_sp->GetByteSize();
+
+ static ConstString g_section_name_eh_frame ("__eh_frame");
+ SectionSP eh_frame_section_sp = text_segment_sp->GetChildren().FindSectionByName(g_section_name_eh_frame);
+ if (eh_frame_section_sp.get()) {
+ *eh_frame = eh_frame_section_sp->GetLoadBaseAddress (&th->GetProcess());
+ *eh_frame_len = eh_frame_section_sp->GetByteSize();
+ } else {
+ *eh_frame = 0;
+ *eh_frame_len = 0;
+ }
+
+ static ConstString g_section_name_unwind_info ("__unwind_info");
+ SectionSP unwind_info_section_sp = text_segment_sp->GetChildren().FindSectionByName(g_section_name_unwind_info);
+ if (unwind_info_section_sp.get()) {
+ *compact_unwind_start = unwind_info_section_sp->GetLoadBaseAddress (&th->GetProcess());
+ *compact_unwind_len = unwind_info_section_sp->GetByteSize();
+ } else {
+ *compact_unwind_start = 0;
+ *compact_unwind_len = 0;
+ }
+ return UNW_ESUCCESS;
+}
+
+static int
+get_proc_bounds (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t ip, lldb_private::unw_word_t *low, lldb_private::unw_word_t *high, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ Address addr;
+ if (!th->GetProcess().ResolveLoadAddress(ip, addr))
+ return -1;
+ SymbolContext sc;
+ if (!th->GetProcess().GetTarget().GetImages().ResolveSymbolContextForAddress (addr, eSymbolContextFunction | eSymbolContextSymbol, sc))
+ return -1;
+ if (sc.function)
+ {
+ lldb::addr_t start, len;
+ start = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(&th->GetProcess());
+ len = sc.function->GetAddressRange().GetByteSize();
+ if (start == LLDB_INVALID_ADDRESS || len == LLDB_INVALID_ADDRESS)
+ return -1;
+ *low = start;
+ *high = start + len;
+ return UNW_ESUCCESS;
+ }
+ if (sc.symbol)
+ {
+ lldb::addr_t start, len;
+ start = sc.symbol->GetAddressRangeRef().GetBaseAddress().GetLoadAddress(&th->GetProcess());
+ len = sc.symbol->GetAddressRangeRef().GetByteSize();
+ if (start == LLDB_INVALID_ADDRESS)
+ return -1;
+ *low = start;
+ if (len != LLDB_INVALID_ADDRESS)
+ *high = start + len;
+ else
+ *high = 0;
+ return UNW_ESUCCESS;
+ }
+ return -1;
+}
+
+static int
+access_raw (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t addr, lldb_private::unw_word_t extent, uint8_t *valp, int write, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ /* FIXME Only support reading for now. */
+ if (write == 1)
+ return -1;
+
+ Error error;
+ if (th->GetProcess().ReadMemory (addr, valp, extent, error) != extent)
+ return -1;
+ return UNW_ESUCCESS;
+}
+
+
+static int
+reg_info (lldb_private::unw_addr_space_t as, lldb_private::unw_regnum_t regnum, lldb_private::unw_regtype_t *type, char *buf, size_t buflen, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ RegisterContext *regc = th->GetRegisterContext();
+ if (regnum > regc->GetRegisterCount())
+ {
+ *type = UNW_NOT_A_REG;
+ return UNW_ESUCCESS;
+ }
+
+ const char *name = regc->GetRegisterName (regnum);
+ if (name == NULL)
+ {
+ *type = UNW_NOT_A_REG;
+ return UNW_ESUCCESS;
+ }
+ strlcpy (buf, name, buflen);
+
+ const lldb::RegisterInfo *reginfo = regc->GetRegisterInfoAtIndex (regnum);
+ if (reginfo == NULL || reginfo->encoding == eEncodingInvalid)
+ {
+ *type = UNW_NOT_A_REG;
+ return UNW_ESUCCESS;
+ }
+ if (reginfo->encoding == eEncodingUint || reginfo->encoding == eEncodingSint)
+ *type = UNW_INTEGER_REG;
+ if (reginfo->encoding == eEncodingIEEE754)
+ *type = UNW_FLOATING_POINT_REG;
+ if (reginfo->encoding == eEncodingVector)
+ *type = UNW_VECTOR_REG;
+
+ return UNW_ESUCCESS;
+}
+
+
+static int
+read_byte_for_edis (uint8_t *buf, uint64_t addr, void *arg)
+{
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ DataBufferHeap onebyte(1, 0);
+ Error error;
+ if (th->GetProcess().ReadMemory (addr, onebyte.GetBytes(), onebyte.GetByteSize(), error) != 1)
+ return -1;
+ *buf = onebyte.GetBytes()[0];
+ return UNW_ESUCCESS;
+}
+
+static int
+instruction_length (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t addr, int *length, void *arg)
+{
+ EDDisassemblerRef disasm;
+ EDInstRef cur_insn;
+
+ if (arg == 0)
+ return -1;
+ Thread *th = (Thread *) arg;
+ const ArchSpec target_arch (th->GetProcess().GetTarget().GetArchitecture ());
+
+ if (target_arch.GetCPUType() == CPU_TYPE_I386)
+ {
+ if (EDGetDisassembler (&disasm, "i386-apple-darwin", kEDAssemblySyntaxX86ATT) != 0)
+ return -1;
+ }
+ else if (target_arch.GetCPUType() == CPU_TYPE_X86_64)
+ {
+ if (EDGetDisassembler (&disasm, "x86_64-apple-darwin", kEDAssemblySyntaxX86ATT) != 0)
+ return -1;
+ }
+ else
+ {
+ return -1;
+ }
+
+ if (EDCreateInsts (&cur_insn, 1, disasm, read_byte_for_edis, addr, arg) != 1)
+ return -1;
+ *length = EDInstByteSize (cur_insn);
+ EDReleaseInst (cur_insn);
+ return UNW_ESUCCESS;
+}
+
+lldb_private::unw_accessors_t
+get_macosx_libunwind_callbacks () {
+ lldb_private::unw_accessors_t ap;
+ bzero (&ap, sizeof (lldb_private::unw_accessors_t));
+ ap.find_proc_info = NULL;
+ ap.put_unwind_info = NULL;
+ ap.get_dyn_info_list_addr = NULL;
+ ap.find_image_info = find_image_info;
+ ap.access_mem = NULL;
+ ap.access_reg = access_reg;
+ ap.access_fpreg = NULL;
+ ap.access_vecreg = NULL;
+ ap.resume = NULL;
+ ap.get_proc_name = get_proc_name;
+ ap.get_proc_bounds = get_proc_bounds;
+ ap.access_raw = access_raw;
+ ap.reg_info = reg_info;
+ ap.proc_is_sigtramp = NULL;
+ ap.proc_is_inferior_function_call = NULL;
+ ap.access_reg_inf_func_call = NULL;
+ ap.instruction_length = instruction_length;
+ return ap;
+}
+
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef liblldb_MacOSXLibunwindCallbacks_cpp_
diff --git a/lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.h b/lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.h
new file mode 100644
index 00000000000..78bd27b2ad3
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/MacOSXLibunwindCallbacks.h
@@ -0,0 +1,22 @@
+//===-- MacOSXLibunwindCallbacks.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MacOSXLibunwindCallbacks_h_
+#define liblldb_MacOSXLibunwindCallbacks_h_
+#if defined(__cplusplus)
+
+namespace lldb_private {
+
+unw_accessors_t get_macosx_libunwind_callbacks ();
+
+} // namespace lldb_utility
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef liblldb_MacOSXLibunwindCallbacks_h_
+
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
new file mode 100644
index 00000000000..df2f7c07f65
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
@@ -0,0 +1,255 @@
+//===-- 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/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Thread.h"
+// Project includes
+#include "StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContextMacOSXFrameBackchain constructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::RegisterContextMacOSXFrameBackchain
+(
+ Thread &thread,
+ StackFrame *frame,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor
+) :
+ RegisterContext (thread, frame),
+ m_cursor (cursor),
+ m_cursor_is_valid (true)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::~RegisterContextMacOSXFrameBackchain()
+{
+}
+
+void
+RegisterContextMacOSXFrameBackchain::Invalidate ()
+{
+ m_cursor_is_valid = false;
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const lldb::RegisterInfo *
+RegisterContextMacOSXFrameBackchain::GetRegisterInfoAtIndex (uint32_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg);
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount();
+}
+
+
+
+const lldb::RegisterSet *
+RegisterContextMacOSXFrameBackchain::GetRegisterSet (uint32_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadRegisterValue (uint32_t reg, Scalar &value)
+{
+ if (!m_cursor_is_valid)
+ return false;
+
+ uint64_t reg_value = LLDB_INVALID_ADDRESS;
+
+ const RegisterInfo *reg_info = m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ return false;
+
+ 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.pc;
+ break;
+
+ default:
+ return false;
+ }
+
+ switch (reg_info->encoding)
+ {
+ case eEncodingUint:
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ value = (uint32_t)reg_value;
+ return true;
+
+ case 8:
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case eEncodingSint:
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ value = (int32_t)reg_value;
+ return true;
+
+ case 8:
+ value = (int64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case eEncodingIEEE754:
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ if (sizeof (float) == sizeof(uint32_t))
+ {
+ value = (uint32_t)reg_value;
+ return true;
+ }
+ else if (sizeof (float) == sizeof(uint64_t))
+ {
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case sizeof (double):
+ if (sizeof (double) == sizeof(uint32_t))
+ {
+ value = (uint32_t)reg_value;
+ return true;
+ }
+ else if (sizeof (double) == sizeof(uint64_t))
+ {
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+
+ case sizeof (long double):
+ if (sizeof (long double) == sizeof(uint32_t))
+ {
+ value = (uint32_t)reg_value;
+ return true;
+ }
+ else if (sizeof (long double) == sizeof(uint64_t))
+ {
+ value = (uint64_t)reg_value;
+ return true;
+ }
+ break;
+ }
+ break;
+ }
+ return false;
+}
+
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
+{
+ Scalar reg_value;
+
+ if (ReadRegisterValue (reg, reg_value))
+ {
+ if (reg_value.GetData(data))
+ {
+ // "reg_value" is local and now "data" points to the data within
+ // "reg_value", so we must make a copy that will live within "data"
+ DataBufferSP data_sp (new DataBufferHeap (data.GetDataStart(), data.GetByteSize()));
+ data.SetData (data_sp, 0, data.GetByteSize());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteRegisterValue (uint32_t reg, const Scalar &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::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
+{
+ // 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/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
new file mode 100644
index 00000000000..f4118c2795d
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
@@ -0,0 +1,83 @@
+//===-- 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,
+ lldb_private::StackFrame *frame,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor);
+
+ virtual
+ ~RegisterContextMacOSXFrameBackchain ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ Invalidate ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb::RegisterSet *
+ GetRegisterSet (uint32_t reg_set);
+
+ virtual bool
+ ReadRegisterValue (uint32_t reg, lldb_private::Scalar &value);
+
+ virtual bool
+ ReadRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegisterValue (uint32_t reg, const lldb_private::Scalar &value);
+
+ virtual bool
+ WriteRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data, uint32_t data_offset);
+
+ 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/lldb/source/Plugins/Process/Utility/UnwindLibUnwind.cpp b/lldb/source/Plugins/Process/Utility/UnwindLibUnwind.cpp
new file mode 100644
index 00000000000..1b6fa58dcd4
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/UnwindLibUnwind.cpp
@@ -0,0 +1,73 @@
+//===-- UnwindLibUnwind.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/Thread.h"
+#include "UnwindLibUnwind.h"
+#include "LibUnwindRegisterContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindLibUnwind::UnwindLibUnwind (Thread &thread, unw_addr_space_t addr_space) :
+ Unwind (thread),
+ m_addr_space (addr_space),
+ m_cursors()
+{
+ m_pc_regnum = thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ m_sp_regnum = thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+}
+
+uint32_t
+UnwindLibUnwind::GetFrameCount()
+{
+ if (m_cursors.empty())
+ {
+ unw_cursor_t cursor;
+ unw_init_remote (&cursor, m_addr_space, &m_thread);
+
+ m_cursors.push_back (cursor);
+
+ while (1)
+ {
+ int stepresult = unw_step (&cursor);
+ if (stepresult > 0)
+ m_cursors.push_back (cursor);
+ else
+ break;
+ }
+ }
+ return m_cursors.size();
+}
+
+bool
+UnwindLibUnwind::GetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
+{
+ const uint32_t frame_count = GetFrameCount();
+ if (idx < frame_count)
+ {
+ int pc_err = unw_get_reg (&m_cursors[idx], m_pc_regnum, &pc);
+ int sp_err = unw_get_reg (&m_cursors[idx], m_sp_regnum, &cfa);
+ return pc_err == UNW_ESUCCESS && sp_err == UNW_ESUCCESS;
+ }
+ return false;
+}
+
+RegisterContext *
+UnwindLibUnwind::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ uint32_t idx = frame->GetID();
+ const uint32_t frame_count = GetFrameCount();
+ if (idx < frame_count)
+ return new LibUnwindRegisterContext (m_thread, frame, m_cursors[idx]);
+ return NULL;
+}
diff --git a/lldb/source/Plugins/Process/Utility/UnwindLibUnwind.h b/lldb/source/Plugins/Process/Utility/UnwindLibUnwind.h
new file mode 100644
index 00000000000..d91f164a2f9
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/UnwindLibUnwind.h
@@ -0,0 +1,66 @@
+//===-- UnwindLibUnwind.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_UnwindLibUnwind_h_
+#define lldb_UnwindLibUnwind_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+#include "libunwind.h"
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Unwind.h"
+
+class UnwindLibUnwind : public lldb_private::Unwind
+{
+public:
+ UnwindLibUnwind (lldb_private::Thread &thread,
+ lldb_private::unw_addr_space_t addr_space);
+
+ virtual
+ ~UnwindLibUnwind()
+ {
+ }
+
+ virtual void
+ Clear()
+ {
+ m_cursors.clear();
+ }
+
+ virtual uint32_t
+ GetFrameCount();
+
+ bool
+ GetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& pc);
+
+ lldb_private::RegisterContext *
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ lldb_private::Thread &
+ GetThread();
+
+private:
+ lldb_private::unw_addr_space_t m_addr_space;
+ std::vector<lldb_private::unw_cursor_t> m_cursors;
+ uint32_t m_pc_regnum;
+ uint32_t m_sp_regnum;
+ //------------------------------------------------------------------
+ // For UnwindLibUnwind only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (UnwindLibUnwind);
+};
+
+#endif // lldb_UnwindLibUnwind_h_
diff --git a/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp b/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
new file mode 100644
index 00000000000..586e3d78864
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
@@ -0,0 +1,243 @@
+//===-- 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/Target/Thread.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "RegisterContextMacOSXFrameBackchain.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain (Thread &thread) :
+ Unwind (thread),
+ m_cursors()
+{
+}
+
+uint32_t
+UnwindMacOSXFrameBackchain::GetFrameCount()
+{
+ if (m_cursors.empty())
+ {
+ const ArchSpec target_arch (m_thread.GetProcess().GetTarget().GetArchitecture ());
+ // Frame zero should always be supplied by the thread...
+ StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (0));
+ if (target_arch == ArchSpec("x86_64"))
+ GetStackFrameData_x86_64 (frame_sp.get());
+ else if (target_arch == ArchSpec("i386"))
+ GetStackFrameData_i386 (frame_sp.get());
+
+ }
+ return m_cursors.size();
+}
+
+bool
+UnwindMacOSXFrameBackchain::GetFrameInfoAtIndex (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;
+}
+
+RegisterContext *
+UnwindMacOSXFrameBackchain::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ uint32_t idx = frame->GetID();
+ const uint32_t frame_count = GetFrameCount();
+ if (idx < frame_count)
+ return new RegisterContextMacOSXFrameBackchain (m_thread, frame, m_cursors[idx]);
+ return NULL;
+}
+
+size_t
+UnwindMacOSXFrameBackchain::GetStackFrameData_i386 (StackFrame *first_frame)
+{
+ m_cursors.clear();
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ typedef struct Frame_i386
+ {
+ uint32_t fp;
+ uint32_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ assert (reg_ctx);
+
+ Cursor cursor;
+ cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
+ cursor.fp = reg_ctx->GetFP (0);
+
+ Frame_i386 frame = { cursor.fp, 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 (m_thread.GetProcess().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;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ addr_range_ptr = first_frame_sc.symbol->GetAddressRangePtr();
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetPC() == 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 && m_thread.GetProcess().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.16llx 0x%16.16llx\n", i, m_cursors[i].pc, m_cursors[i].fp);
+// }
+ return m_cursors.size();
+}
+
+
+size_t
+UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64 (StackFrame *first_frame)
+{
+ m_cursors.clear();
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ typedef struct Frame_x86_64
+ {
+ uint64_t fp;
+ uint64_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ 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 (m_thread.GetProcess().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;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ addr_range_ptr = first_frame_sc.symbol->GetAddressRangePtr();
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetPC() == 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 (m_thread.GetProcess().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/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h b/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
new file mode 100644
index 00000000000..86ba6e7ae7f
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
@@ -0,0 +1,77 @@
+//===-- 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()
+ {
+ }
+
+ virtual void
+ Clear()
+ {
+ m_cursors.clear();
+ }
+
+ virtual uint32_t
+ GetFrameCount();
+
+ bool
+ GetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& pc);
+
+ lldb_private::RegisterContext *
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ lldb_private::Thread &
+ GetThread();
+
+protected:
+ friend class RegisterContextMacOSXFrameBackchain;
+
+ typedef 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 (lldb_private::StackFrame *first_frame);
+
+ size_t
+ GetStackFrameData_x86_64 (lldb_private::StackFrame *first_frame);
+
+ //------------------------------------------------------------------
+ // For UnwindMacOSXFrameBackchain only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (UnwindMacOSXFrameBackchain);
+};
+
+#endif // lldb_UnwindMacOSXFrameBackchain_h_
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/include/libunwind.h b/lldb/source/Plugins/Process/Utility/libunwind/include/libunwind.h
new file mode 100644
index 00000000000..63cc8ba2366
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/include/libunwind.h
@@ -0,0 +1,509 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- libunwind.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// C interface to libuwind
+//
+// Source compatible with Level 1 Base ABI documented at:
+// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef __LIBUNWIND__
+#define __LIBUNWIND__
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <mach/mach_types.h>
+#include <Availability.h>
+
+namespace lldb_private {
+
+#pragma mark Error codes
+
+enum {
+ UNW_ESUCCESS = 0, /* no error */
+ UNW_EUNSPEC = -6540, /* unspecified (general) error */
+ UNW_ENOMEM = -6541, /* out of memory */
+ UNW_EBADREG = -6542, /* bad register number */
+ UNW_EREADONLYREG = -6543, /* attempt to write read-only register */
+ UNW_ESTOPUNWIND = -6544, /* stop unwinding */
+ UNW_EINVALIDIP = -6545, /* invalid IP */
+ UNW_EBADFRAME = -6546, /* bad frame */
+ UNW_EINVAL = -6547, /* unsupported operation or bad value */
+ UNW_EBADVERSION = -6548, /* unwind info has unsupported version */
+ UNW_ENOINFO = -6549, /* no unwind info found */
+ UNW_EREGUNAVAILABLE = -6550 /* contents of requested reg are not available */
+};
+
+#pragma mark General data structures
+
+struct unw_context_t { uint64_t data[128]; };
+typedef struct unw_context_t unw_context_t;
+
+struct unw_cursor_t { uint64_t data[140]; };
+typedef struct unw_cursor_t unw_cursor_t;
+
+enum unw_as_type { UNW_LOCAL, UNW_REMOTE };
+struct unw_addr_space
+{
+ enum unw_as_type type;
+ uint8_t data[];
+};
+typedef struct unw_addr_space* unw_addr_space_t;
+
+typedef int unw_regnum_t;
+typedef uint64_t unw_word_t;
+typedef double unw_fpreg_t;
+
+enum unw_vecreg_format {
+ UNW_VECREG_SIGNED,
+ UNW_VECREG_UNSIGNED,
+ UNW_VECREG_FLOAT
+};
+
+typedef struct
+{
+ union {
+ double doubles[8];
+ float floats [16];
+
+ uint64_t dwords [8];
+ uint32_t words [16];
+ uint16_t hwords [32];
+ uint8_t bytes [64];
+ } data;
+ uint16_t unit_size; // bits
+ uint16_t num_units;
+ uint8_t format;
+} unw_vecreg_t;
+
+struct unw_proc_info_t
+{
+ unw_word_t start_ip; /* start address of function */
+ unw_word_t end_ip; /* address after end of function */
+ unw_word_t lsda; /* address of language specific data area, or zero if not used */
+ unw_word_t handler; /* personality routine, or zero if not used */
+ unw_word_t gp; /* not used */
+ unw_word_t flags; /* not used */
+ uint32_t format; /* compact unwind encoding, or zero if none */
+ uint32_t unwind_info_size; /* size of dwarf unwind info, or zero if none */
+ unw_word_t unwind_info; /* address of dwarf unwind info, or zero if none */
+ unw_word_t extra; /* mach_header of mach-o image containing function */
+};
+typedef struct unw_proc_info_t unw_proc_info_t;
+
+#pragma mark Local API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int unw_getcontext(unw_context_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_init_local(unw_cursor_t*, unw_context_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_step(unw_cursor_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_get_reg(unw_cursor_t*, unw_regnum_t, unw_word_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_get_fpreg(unw_cursor_t*, unw_regnum_t, unw_fpreg_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_set_reg(unw_cursor_t*, unw_regnum_t, unw_word_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_set_fpreg(unw_cursor_t*, unw_regnum_t, unw_fpreg_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_resume(unw_cursor_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+
+extern const char* unw_regname(unw_cursor_t*, unw_regnum_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_get_proc_info(unw_cursor_t*, unw_proc_info_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_is_fpreg(unw_cursor_t*, unw_regnum_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_is_signal_frame(unw_cursor_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_get_proc_name(unw_cursor_t*, char*, size_t, unw_word_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+//extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*);
+
+
+#pragma mark Remote data structures
+
+typedef enum {
+ UNW_NOT_A_REG = 0,
+ UNW_INTEGER_REG,
+ UNW_FLOATING_POINT_REG,
+ UNW_VECTOR_REG,
+ UNW_OTHER_REG
+} unw_regtype_t;
+
+typedef enum {
+ UNW_TARGET_UNSPECIFIED = 0,
+ UNW_TARGET_I386,
+ UNW_TARGET_X86_64,
+ UNW_TARGET_PPC,
+ UNW_TARGET_ARM
+} unw_targettype_t;
+
+typedef enum {
+ UNW_LOG_LEVEL_NONE = 0x00000000,
+ UNW_LOG_LEVEL_INFO = 0x00000001,
+ UNW_LOG_LEVEL_API = 0x00000002,
+ UNW_LOG_LEVEL_VERBOSE = 0x00000004,
+ UNW_LOG_LEVEL_TIMINGS = 0x00000008,
+ UNW_LOG_LEVEL_DEBUG = 0x00000010,
+ UNW_LOG_LEVEL_ALL = 0x0FFFFFFF
+} unw_log_level_t;
+
+typedef enum {
+ UNW_CACHE_NONE = 0,
+ UNW_CACHE_GLOBAL,
+ UNW_CACHE_PER_THREAD
+} unw_caching_policy_t;
+
+typedef struct {
+ int (*find_proc_info)(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pip, int need_unwind_info, void *arg);
+ int (*put_unwind_info)(unw_addr_space_t as, unw_proc_info_t *pip, void *arg);
+ int (*get_dyn_info_list_addr)(unw_addr_space_t as, unw_word_t *dilap, void *arg);
+
+ // Reads or writes a memory object the size of a target pointer.
+ // Byte-swaps if necessary.
+ int (*access_mem)(unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, int write, void *arg);
+
+ // Register contents sent as-is (i.e. not byte-swapped).
+ // Register numbers are the driver program's numbering scheme as
+ // determined by the reg_info callbacks; libunwind will interrogate
+ // the driver program to figure out which numbers it uses to refer to
+ // which registers.
+ int (*access_reg)(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valp, int write, void *arg);
+ int (*access_fpreg)(unw_addr_space_t as, unw_regnum_t regnum, unw_fpreg_t *valp, int write, void *arg);
+ int (*resume)(unw_addr_space_t as, unw_cursor_t *cp, void *arg);
+ int (*get_proc_name)(unw_addr_space_t as, unw_word_t addr, char *bufp, size_t buf_len, unw_word_t *offp, void *arg);
+
+
+ // Added to find the start of the image (executable, bundle, dylib, etc)
+ // for a given address.
+ // as - The address space to use
+ // ip - The address libunwind wants to know about
+ // mh - The Mach-O header address for this image
+ // text_start - The start of __TEXT segment (all its sections)
+ // text_end - The end address of __TEXT segment (all its sections)
+ // eh_frame - The start of __TEXT,__eh_frame
+ // eh_frame_len - The length of __TEXT,__eh_frame
+ // compact_unwind_start - The start of __TEXT,__unwind_info
+ // compact_unwind_len - The length of __TEXT,__unwind_info
+ // arg - The driver-provided generic argument
+ // All addresses are the in-memory, slid, addresses.
+ // If eh_frame or unwind_info are missing, addr and len is returned as 0.
+ int (*find_image_info)(unw_addr_space_t as, unw_word_t ip, unw_word_t *mh,
+ unw_word_t *text_start, unw_word_t *text_end,
+ unw_word_t *eh_frame, unw_word_t *eh_frame_len,
+ unw_word_t *compact_unwind_start,
+ unw_word_t *compact_unwind_len, void *arg);
+
+ // Added to get the start and end address of a function without needing
+ // all of the information (and potential allocation) that the
+ // find_proc_info() call entails.
+ // as - The address space to use
+ // ip - The address libunwind wants to know about
+ // low - The start address of the function at 'ip'
+ // high - The first address past the function at 'ip'
+ // arg - The driver-provided generic argument
+ // If HIGH is unknown, it should be set to 0. All addresses
+ // are the in-memory, slid, addresses.
+ int (*get_proc_bounds)(unw_addr_space_t as, unw_word_t ip,
+ unw_word_t *low, unw_word_t *high, void *arg);
+
+ // Added to support accessing non-word-size memory objects across
+ // platforms. No byte swapping should be done.
+ // as - The address space to use
+ // addr - The starting address to access
+ // extent - The extent of the region to access, in bytes
+ // valp - The local region to be written from / read into
+ // write - non-zero if the data is to be written into the target
+ // rather than read
+ // arg - The driver-provided generic argument (see unw_init_remote)
+ int (*access_raw)(unw_addr_space_t as, unw_word_t addr, unw_word_t extent,
+ uint8_t *valp, int write, void *arg);
+
+ // Added to support identifying registers.
+ // libunwind will interrogate the driver program via this callback to
+ // identify what register numbers it is using; the register names are
+ // used to correlate that the driver program's register numbers with
+ // libunwind's internal register numbers. The driver program should
+ // use its own register numbers when requesting registers with
+ // unw_get_reg() and libunwind will provide the driver program's
+ // register numbers to the access_reg callback function.
+ // as - The address space to use
+ // regnum - The register number
+ // type - Write the register type to this address
+ // For a non-existent register, return UNW_ESUCCESS but
+ // write UNW_NOT_A_REG to type
+ // buf - If non-NULL, the register name is written to this address
+ // buf_len - The size of the buffer provided for the register name
+ // arg - The driver-provided generic argument (see unw_init_remote)
+ int (*reg_info)(unw_addr_space_t as, unw_regnum_t regnum,
+ unw_regtype_t* type, char *bufp, size_t buf_len, void *arg);
+
+ // Added to read a vector register's value from the remote machine.
+ // as - The address space to use
+ // regnum - The register number
+ // valp - The local region to be written from / read into
+ // write - non-zero if the data is to be written into the target
+ // rather than read
+ // arg - The driver-specified generic argument
+ int (*access_vecreg)(unw_addr_space_t as, unw_regnum_t regnum,
+ unw_vecreg_t* valp, int write, void *arg);
+
+ // Added to identify if an unwind cursor is pointing to _sigtramp().
+ // After a _sigtramp we have an entire register set available and we should
+ // return any of the registers requested.
+ // as - The address space to use
+ // ip - The address of the function libunwind is examining
+ // arg - The driver-provided generic argument
+ // This function returns non-zero if ip is in _sigtramp.
+ int (*proc_is_sigtramp) (unw_addr_space_t as, unw_word_t ip, void *arg);
+
+ // Added to identify if an unwind cursor is pointing to a debugger's
+ // inferior function call dummy frame.
+ // The driver program will need to provide the full register set (via the
+ // standard access_reg callback) for the function that was executing
+ // when the inferior function call was made; it will use these register
+ // values and not try to unwind out of the inferior function call dummy
+ // frame.
+ // After a inf func call we have an entire register set available and
+ // we should return any of the registers requested.
+ // as - The address space to use
+ // ip - The address of the function libunwind is examining
+ // sp - The stack pointer value of the frame
+ // arg - The driver-provided generic argument (see unw_init_remote)
+ // This function returns non-zero if ip/sp is an inferior function call
+ // dummy frame.
+ int (*proc_is_inferior_function_call) (unw_addr_space_t as, unw_word_t ip,
+ unw_word_t sp, void *arg);
+
+ // Added to retrieve a register value from a above a debugger's inferior
+ // function call dummy frame. Similar to _sigtramp but the debugger will
+ // have the register context squirreled away in its own memory (or possibly
+ // saved on the stack somewhere).
+ // May be NULL if the program being unwound will not have a debugger
+ // calling functions mid-execution.
+ // as - The address space to use
+ // ip - The pc value for the dummy frame
+ // sp - The stack pointer for the dummy frame
+ // regnum - The register number in the driver program's register
+ // numbering scheme.
+ // valp - Pointer to a word of memory to be read/written
+ // write - Non-zero if libunwind is writing a new value to the reg,
+ // else it is reading the contents of that register.
+ // arg - The driver-provided generic argument (see unw_init_remote)
+ int (*access_reg_inf_func_call)(unw_addr_space_t as, unw_word_t ip,
+ unw_word_t sp, unw_regnum_t regnum,
+ unw_word_t *valp, int write, void *arg);
+
+ // Added to iterate over unknown assembly instructions when analyzing a
+ // function prologue. Needed for ISAs with variable length instructions
+ // (i386, x86_64) or multiple instruction sizes (arm, thumb).
+ // Returns zero if the instruction length was successfully measured.
+ // as - The address space to use
+ // addr - The address of the instruction being measured
+ // length - Set to the length of the instruction
+ // arg - The driver-provided generic argument (see unw_init_remote)
+ int (*instruction_length)(unw_addr_space_t as, unw_word_t addr,
+ int *length, void *arg);
+
+} unw_accessors_t;
+
+extern int unw_init_remote(unw_cursor_t*, unw_addr_space_t, void*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern unw_accessors_t* unw_get_accessors(unw_addr_space_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern unw_addr_space_t unw_create_addr_space(unw_accessors_t*, unw_targettype_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern void unw_flush_caches(unw_addr_space_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern int unw_set_caching_policy(unw_addr_space_t, unw_caching_policy_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern void unw_destroy_addr_space(unw_addr_space_t asp) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+extern void unw_set_logging_level(unw_addr_space_t, FILE *, unw_log_level_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+
+// Should be called when remote unwinding if a bundle in the remote process
+// is unloaded
+extern void unw_image_was_unloaded(unw_addr_space_t, unw_word_t mh) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+
+// Try to discern where the function's prologue instructions end
+// start - start address of the function, required
+// end - first address beyond the function, or zero if unknown
+// endofprologue - set to the address after the last prologue instruction if successful
+extern int unw_end_of_prologue_setup(unw_cursor_t*, unw_word_t start, unw_word_t end, unw_word_t *endofprologue) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_NA);
+
+/*
+ * Dynamic unwinding API
+ * NOT IMPLEMENTED on Mac OS X
+ * extern void _U_dyn_register(unw_dyn_info_t*);
+ * extern void _U_dyn_cancel(unw_dyn_info_t*);
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma mark Register numbers
+
+// architecture independent register numbers
+enum {
+ UNW_REG_IP = -1, // instruction pointer
+ UNW_REG_SP = -2, // stack pointer
+};
+
+
+// 32-bit x86 registers
+enum {
+ UNW_X86_EAX = 0,
+ UNW_X86_ECX = 1,
+ UNW_X86_EDX = 2,
+ UNW_X86_EBX = 3,
+ UNW_X86_EBP = 4,
+ UNW_X86_ESP = 5,
+ UNW_X86_ESI = 6,
+ UNW_X86_EDI = 7
+};
+
+
+// 64-bit x86_64 registers
+enum {
+ UNW_X86_64_RAX = 0,
+ UNW_X86_64_RDX = 1,
+ UNW_X86_64_RCX = 2,
+ UNW_X86_64_RBX = 3,
+ UNW_X86_64_RSI = 4,
+ UNW_X86_64_RDI = 5,
+ UNW_X86_64_RBP = 6,
+ UNW_X86_64_RSP = 7,
+ UNW_X86_64_R8 = 8,
+ UNW_X86_64_R9 = 9,
+ UNW_X86_64_R10 = 10,
+ UNW_X86_64_R11 = 11,
+ UNW_X86_64_R12 = 12,
+ UNW_X86_64_R13 = 13,
+ UNW_X86_64_R14 = 14,
+ UNW_X86_64_R15 = 15
+};
+
+
+// 32-bit ppc register numbers
+enum {
+ UNW_PPC_R0 = 0,
+ UNW_PPC_R1 = 1,
+ UNW_PPC_R2 = 2,
+ UNW_PPC_R3 = 3,
+ UNW_PPC_R4 = 4,
+ UNW_PPC_R5 = 5,
+ UNW_PPC_R6 = 6,
+ UNW_PPC_R7 = 7,
+ UNW_PPC_R8 = 8,
+ UNW_PPC_R9 = 9,
+ UNW_PPC_R10 = 10,
+ UNW_PPC_R11 = 11,
+ UNW_PPC_R12 = 12,
+ UNW_PPC_R13 = 13,
+ UNW_PPC_R14 = 14,
+ UNW_PPC_R15 = 15,
+ UNW_PPC_R16 = 16,
+ UNW_PPC_R17 = 17,
+ UNW_PPC_R18 = 18,
+ UNW_PPC_R19 = 19,
+ UNW_PPC_R20 = 20,
+ UNW_PPC_R21 = 21,
+ UNW_PPC_R22 = 22,
+ UNW_PPC_R23 = 23,
+ UNW_PPC_R24 = 24,
+ UNW_PPC_R25 = 25,
+ UNW_PPC_R26 = 26,
+ UNW_PPC_R27 = 27,
+ UNW_PPC_R28 = 28,
+ UNW_PPC_R29 = 29,
+ UNW_PPC_R30 = 30,
+ UNW_PPC_R31 = 31,
+ UNW_PPC_F0 = 32,
+ UNW_PPC_F1 = 33,
+ UNW_PPC_F2 = 34,
+ UNW_PPC_F3 = 35,
+ UNW_PPC_F4 = 36,
+ UNW_PPC_F5 = 37,
+ UNW_PPC_F6 = 38,
+ UNW_PPC_F7 = 39,
+ UNW_PPC_F8 = 40,
+ UNW_PPC_F9 = 41,
+ UNW_PPC_F10 = 42,
+ UNW_PPC_F11 = 43,
+ UNW_PPC_F12 = 44,
+ UNW_PPC_F13 = 45,
+ UNW_PPC_F14 = 46,
+ UNW_PPC_F15 = 47,
+ UNW_PPC_F16 = 48,
+ UNW_PPC_F17 = 49,
+ UNW_PPC_F18 = 50,
+ UNW_PPC_F19 = 51,
+ UNW_PPC_F20 = 52,
+ UNW_PPC_F21 = 53,
+ UNW_PPC_F22 = 54,
+ UNW_PPC_F23 = 55,
+ UNW_PPC_F24 = 56,
+ UNW_PPC_F25 = 57,
+ UNW_PPC_F26 = 58,
+ UNW_PPC_F27 = 59,
+ UNW_PPC_F28 = 60,
+ UNW_PPC_F29 = 61,
+ UNW_PPC_F30 = 62,
+ UNW_PPC_F31 = 63,
+ UNW_PPC_MQ = 64,
+ UNW_PPC_LR = 65,
+ UNW_PPC_CTR = 66,
+ UNW_PPC_AP = 67,
+ UNW_PPC_CR0 = 68,
+ UNW_PPC_CR1 = 69,
+ UNW_PPC_CR2 = 70,
+ UNW_PPC_CR3 = 71,
+ UNW_PPC_CR4 = 72,
+ UNW_PPC_CR5 = 73,
+ UNW_PPC_CR6 = 74,
+ UNW_PPC_CR7 = 75,
+ UNW_PPC_XER = 76,
+ UNW_PPC_V0 = 77,
+ UNW_PPC_V1 = 78,
+ UNW_PPC_V2 = 79,
+ UNW_PPC_V3 = 80,
+ UNW_PPC_V4 = 81,
+ UNW_PPC_V5 = 82,
+ UNW_PPC_V6 = 83,
+ UNW_PPC_V7 = 84,
+ UNW_PPC_V8 = 85,
+ UNW_PPC_V9 = 86,
+ UNW_PPC_V10 = 87,
+ UNW_PPC_V11 = 88,
+ UNW_PPC_V12 = 89,
+ UNW_PPC_V13 = 90,
+ UNW_PPC_V14 = 91,
+ UNW_PPC_V15 = 92,
+ UNW_PPC_V16 = 93,
+ UNW_PPC_V17 = 94,
+ UNW_PPC_V18 = 95,
+ UNW_PPC_V19 = 96,
+ UNW_PPC_V20 = 97,
+ UNW_PPC_V21 = 98,
+ UNW_PPC_V22 = 99,
+ UNW_PPC_V23 = 100,
+ UNW_PPC_V24 = 101,
+ UNW_PPC_V25 = 102,
+ UNW_PPC_V26 = 103,
+ UNW_PPC_V27 = 104,
+ UNW_PPC_V28 = 105,
+ UNW_PPC_V29 = 106,
+ UNW_PPC_V30 = 107,
+ UNW_PPC_V31 = 108,
+ UNW_PPC_VRSAVE = 109,
+ UNW_PPC_VSCR = 110,
+ UNW_PPC_SPE_ACC = 111,
+ UNW_PPC_SPEFSCR = 112
+
+};
+
+
+}; // namespace lldb_private
+
+
+#endif
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/include/mach-o/compact_unwind_encoding.h b/lldb/source/Plugins/Process/Utility/libunwind/include/mach-o/compact_unwind_encoding.h
new file mode 100644
index 00000000000..bee2ad578d6
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/include/mach-o/compact_unwind_encoding.h
@@ -0,0 +1,212 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- compact_unwind_encoding.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef __COMPACT_UNWIND_ENCODING__
+#define __COMPACT_UNWIND_ENCODING__
+
+#include <stdint.h>
+
+namespace lldb_private {
+
+//
+// Each final linked mach-o image has an optional __TEXT, __unwind_info section.
+// This section is much smaller and faster to use than the __eh_frame section.
+//
+
+
+
+//
+// Compilers usually emit standard Dwarf FDEs. The linker recognizes standard FDEs and
+// synthesizes a matching compact_unwind_encoding_t and adds it to the __unwind_info table.
+// It is also possible for the compiler to emit __unwind_info entries for functions that
+// have different unwind requirements at different ranges in the function.
+//
+typedef uint32_t compact_unwind_encoding_t;
+
+
+
+//
+// The __unwind_info section is laid out for an efficient two level lookup.
+// The header of the section contains a coarse index that maps function address
+// to the page (4096 byte block) containing the unwind info for that function.
+//
+
+#define UNWIND_SECTION_VERSION 1
+struct unwind_info_section_header
+{
+ uint32_t version; // UNWIND_SECTION_VERSION
+ uint32_t commonEncodingsArraySectionOffset;
+ uint32_t commonEncodingsArrayCount;
+ uint32_t personalityArraySectionOffset;
+ uint32_t personalityArrayCount;
+ uint32_t indexSectionOffset;
+ uint32_t indexCount;
+ // compact_unwind_encoding_t[]
+ // uintptr_t personalities[]
+ // unwind_info_section_header_index_entry[]
+ // unwind_info_section_header_lsda_index_entry[]
+};
+
+struct unwind_info_section_header_index_entry
+{
+ uint32_t functionOffset;
+ uint32_t secondLevelPagesSectionOffset; // section offset to start of regular or compress page
+ uint32_t lsdaIndexArraySectionOffset; // section offset to start of lsda_index array for this range
+};
+
+struct unwind_info_section_header_lsda_index_entry
+{
+ uint32_t functionOffset;
+ uint32_t lsdaOffset;
+};
+
+//
+// There are two kinds of second level index pages: regular and compressed.
+// A compressed page can hold up to 1021 entries, but it cannot be used
+// if too many different encoding types are used. The regular page holds
+// 511 entries.
+//
+
+struct unwind_info_regular_second_level_entry
+{
+ uint32_t functionOffset;
+ compact_unwind_encoding_t encoding;
+};
+
+#define UNWIND_SECOND_LEVEL_REGULAR 2
+struct unwind_info_regular_second_level_page_header
+{
+ uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
+ uint16_t entryPageOffset;
+ uint16_t entryCount;
+ // entry array
+};
+
+#define UNWIND_SECOND_LEVEL_COMPRESSED 3
+struct unwind_info_compressed_second_level_page_header
+{
+ uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED
+ uint16_t entryPageOffset;
+ uint16_t entryCount;
+ uint16_t encodingsPageOffset;
+ uint16_t encodingsCount;
+ // 32-bit entry array
+ // encodings array
+};
+
+#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
+#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF)
+
+
+
+// architecture independent bits
+enum {
+ UNWIND_IS_NOT_FUNCTION_START = 0x80000000,
+ UNWIND_HAS_LSDA = 0x40000000,
+ UNWIND_PERSONALITY_MASK = 0x30000000,
+};
+
+
+// x86_64
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=dwarf
+// rbp based:
+// 15-bits (5*3-bits per reg) register permutation
+// 8-bits for stack offset
+// frameless:
+// 8-bits stack size
+// 3-bits stack adjust
+// 3-bits register count
+// 10-bits register permutation
+//
+enum {
+ UNWIND_X86_64_MODE_MASK = 0x0F000000,
+ UNWIND_X86_64_MODE_COMPATIBILITY = 0x00000000,
+ UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
+ UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
+ UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
+ UNWIND_X86_64_MODE_DWARF = 0x04000000,
+
+ UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
+ UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
+
+ UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
+ UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
+ UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
+ UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
+
+ UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+};
+
+enum {
+ UNWIND_X86_64_REG_NONE = 0,
+ UNWIND_X86_64_REG_RBX = 1,
+ UNWIND_X86_64_REG_R12 = 2,
+ UNWIND_X86_64_REG_R13 = 3,
+ UNWIND_X86_64_REG_R14 = 4,
+ UNWIND_X86_64_REG_R15 = 5,
+ UNWIND_X86_64_REG_RBP = 6,
+};
+
+
+// x86
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=dwarf
+// ebp based:
+// 15-bits (5*3-bits per reg) register permutation
+// 8-bits for stack offset
+// frameless:
+// 8-bits stack size
+// 3-bits stack adjust
+// 3-bits register count
+// 10-bits register permutation
+//
+enum {
+ UNWIND_X86_MODE_MASK = 0x0F000000,
+ UNWIND_X86_MODE_COMPATIBILITY = 0x00000000,
+ UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
+ UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
+ UNWIND_X86_MODE_STACK_IND = 0x03000000,
+ UNWIND_X86_MODE_DWARF = 0x04000000,
+
+ UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
+ UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
+
+ UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
+ UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
+ UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
+ UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
+
+ UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+};
+
+enum {
+ UNWIND_X86_REG_NONE = 0,
+ UNWIND_X86_REG_EBX = 1,
+ UNWIND_X86_REG_ECX = 2,
+ UNWIND_X86_REG_EDX = 3,
+ UNWIND_X86_REG_EDI = 4,
+ UNWIND_X86_REG_ESI = 5,
+ UNWIND_X86_REG_EBP = 6,
+};
+
+}; // namespace lldb_private
+
+#endif
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/include/unwind.h b/lldb/source/Plugins/Process/Utility/libunwind/include/unwind.h
new file mode 100644
index 00000000000..80b9d2881c2
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/include/unwind.h
@@ -0,0 +1,213 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- unwind.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// C interface to libuwind
+//
+// Source compatible with Level 1 Base ABI documented at:
+// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef __UNWIND_H__
+#define __UNWIND_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <Availability.h>
+
+namespace lldb_private {
+
+typedef enum {
+ _URC_NO_REASON = 0,
+ _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+ _URC_FATAL_PHASE2_ERROR = 2,
+ _URC_FATAL_PHASE1_ERROR = 3,
+ _URC_NORMAL_STOP = 4,
+ _URC_END_OF_STACK = 5,
+ _URC_HANDLER_FOUND = 6,
+ _URC_INSTALL_CONTEXT = 7,
+ _URC_CONTINUE_UNWIND = 8
+} _Unwind_Reason_Code;
+
+typedef enum {
+ _UA_SEARCH_PHASE = 1,
+ _UA_CLEANUP_PHASE = 2,
+ _UA_HANDLER_FRAME = 4,
+ _UA_FORCE_UNWIND = 8,
+ _UA_END_OF_STACK = 16 // gcc extension to C++ ABI
+} _Unwind_Action;
+
+
+struct _Unwind_Context; // opaque
+struct _Unwind_Exception; // forward declaration
+
+struct _Unwind_Exception {
+ uint64_t exception_class;
+ void (*exception_cleanup)(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc);
+ uintptr_t private_1; // non-zero means forced unwind
+ uintptr_t private_2; // holds sp that phase1 found for phase2 to use
+};
+
+
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+ (int version,
+ _Unwind_Action actions,
+ uint64_t exceptionClass,
+ struct _Unwind_Exception* exceptionObject,
+ struct _Unwind_Context* context,
+ void* stop_parameter );
+
+
+typedef _Unwind_Reason_Code (*__personality_routine)
+ (int version,
+ _Unwind_Action actions,
+ uint64_t exceptionClass,
+ struct _Unwind_Exception* exceptionObject,
+ struct _Unwind_Context* context);
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// The following are the base functions documented by the C++ ABI
+//
+#if __arm__
+ extern _Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception* exception_object);
+ extern void _Unwind_SjLj_Resume(struct _Unwind_Exception* exception_object);
+#else
+ extern _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception* exception_object);
+ extern void _Unwind_Resume(struct _Unwind_Exception* exception_object);
+#endif
+extern void _Unwind_DeleteException(struct _Unwind_Exception* exception_object);
+extern uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index);
+extern void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value);
+extern uintptr_t _Unwind_GetIP(struct _Unwind_Context* context);
+extern void _Unwind_SetIP(struct _Unwind_Context*, uintptr_t new_value);
+extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context);
+extern uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context);
+#if __arm__
+ extern _Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter );
+#else
+ extern _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter );
+#endif
+
+#if __arm__
+ typedef struct _Unwind_FunctionContext* _Unwind_FunctionContext_t;
+ extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc);
+ extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc);
+#endif
+
+//
+// The following are semi-suppoted extensions to the C++ ABI
+//
+
+
+//
+// called by __cxa_rethrow().
+//
+#if __arm__
+ extern _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception* exception_object);
+#else
+ extern _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception* exception_object);
+#endif
+
+
+//
+// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the
+// _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack
+// or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON.
+//
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context*, void*);
+extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*);
+
+
+//
+// _Unwind_GetCFA is a gcc extension that can be called from within a personality
+// handler to get the CFA (stack pointer before call) of current frame.
+//
+extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context*);
+
+
+//
+// _Unwind_GetIPInfo is a gcc extension that can be called from within a personality
+// handler. Similar to _Unwind_GetIP() but also returns in *ipBefore a non-zero
+// value if the instruction pointer is at or before the instruction causing
+// the unwind. Normally, in a function call, the IP returned is the return address
+// which is after the call instruction and may be past the end of the function
+// containing the call instruction.
+//
+extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore);
+
+
+//
+// __register_frame() is used with dynamically generated code to register the FDE
+// for a generated (JIT) code. The FDE must use pc-rel addressing to point to its
+// function and optional LSDA. __register_frame() has existed in all versions of
+// Mac OS X, but in 10.4 and 10.5 it was buggy and did not actually register the
+// FDE with the unwinder. In 10.6 and later it does register properly.
+//
+extern void __register_frame(const void* fde);
+extern void __deregister_frame(const void* fde);
+
+
+//
+// _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has
+// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind info"
+// which the runtime uses in preference to dwarf unwind info. This function
+// will only work if the target function has an FDE but no compact unwind info.
+//
+struct dwarf_eh_bases
+{
+ uintptr_t tbase;
+ uintptr_t dbase;
+ uintptr_t func;
+};
+extern const void* _Unwind_Find_FDE(const void* pc, struct dwarf_eh_bases*);
+
+
+//
+// This function attempts to find the start (address of first instruction) of
+// a function given an address inside the function. It only works if the function
+// has an FDE (dwarf unwind info).
+// This function is unimplemented on Mac OS X 10.6 and later. Instead, use
+// _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result.
+extern void* _Unwind_FindEnclosingFunction(void* pc);
+
+
+// Mac OS X does not support text-rel and data-rel addressing so these functions are unimplemented
+extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context) __attribute__((unavailable));
+extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context) __attribute__((unavailable));
+
+
+
+// Mac OS X 10.4 and 10.5 had implementations of these functions in libgcc_s.dylib,
+// but they never worked. These functions are no longer available.
+extern void __register_frame_info_bases(const void* fde, void* ob, void* tb, void* db) __attribute__((unavailable));
+extern void __register_frame_info(const void* fde, void* ob) __attribute__((unavailable));
+extern void __register_frame_info_table_bases(const void* fde, void* ob,void* tb, void* db) __attribute__((unavailable));
+extern void __register_frame_info_table(const void* fde, void* ob) __attribute__((unavailable));
+extern void __register_frame_table(const void* fde) __attribute__((unavailable));
+extern void* __deregister_frame_info(const void* fde) __attribute__((unavailable));
+extern void* __deregister_frame_info_bases(const void* fde) __attribute__((unavailable));
+
+
+#ifdef __cplusplus
+}
+#endif
+
+}; // namespace lldb_private
+
+#endif // __UNWIND_H__
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp
new file mode 100644
index 00000000000..5173dc0068e
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/AddressSpace.hpp
@@ -0,0 +1,456 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- AddressSpace.hpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//
+// C++ interface to lower levels of libuwind
+//
+
+#ifndef __ADDRESSSPACE_HPP__
+#define __ADDRESSSPACE_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <mach-o/loader.h>
+#include <mach-o/getsect.h>
+#if !defined (SUPPORT_REMOTE_UNWINDING)
+#include <mach-o/dyld_priv.h>
+#endif
+#include <mach/ppc/thread_status.h>
+#include <mach/i386/thread_status.h>
+#include <Availability.h>
+
+#include "FileAbstraction.hpp"
+#include "libunwind.h"
+#include "InternalMacros.h"
+#include "dwarf2.h"
+#include "RemoteProcInfo.hpp"
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+bool _dyld_find_unwind_sections(void* addr, void* info)
+{
+ assert("unwinding with a non-remote process not supported.");
+ return false;
+}
+#endif // SUPPORT_REMOTE_UNWINDING
+
+namespace lldb_private {
+
+///
+/// LocalAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
+/// in the same process. It compiles away and making local unwinds very fast.
+///
+class LocalAddressSpace
+{
+public:
+
+ #if __LP64__
+ typedef uint64_t pint_t;
+ typedef int64_t sint_t;
+ #else
+ typedef uint32_t pint_t;
+ typedef int32_t sint_t;
+ #endif
+ int getBytes(pint_t addr, pint_t extent, uint8_t* buf) { memcpy(buf, (void*)addr, extent); return 1; }
+ uint8_t get8(pint_t addr) { return *((uint8_t*)addr); }
+ uint16_t get16(pint_t addr) { return *((uint16_t*)addr); }
+ uint32_t get32(pint_t addr) { return *((uint32_t*)addr); }
+ uint64_t get64(pint_t addr) { return *((uint64_t*)addr); }
+ double getDouble(pint_t addr) { return *((double*)addr); }
+ v128 getVector(pint_t addr) { return *((v128*)addr); }
+
+ uint8_t get8(pint_t addr, int& err) { return *((uint8_t*)addr); err = 0; }
+ uint16_t get16(pint_t addr, int& err) { return *((uint16_t*)addr); err = 0; }
+ uint32_t get32(pint_t addr, int& err) { return *((uint32_t*)addr); err = 0; }
+ uint64_t get64(pint_t addr, int& err) { return *((uint64_t*)addr); err = 0; }
+ double getDouble(pint_t addr, int& err) { return *((double*)addr); err = 0; }
+ v128 getVector(pint_t addr, int& err) { return *((v128*)addr); err = 0; }
+
+ uintptr_t getP(pint_t addr);
+ uintptr_t getP(pint_t addr, int &err);
+ static uint64_t getULEB128(pint_t& addr, pint_t end);
+ static int64_t getSLEB128(pint_t& addr, pint_t end);
+
+ pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
+ bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
+ bool findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart);
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+ RemoteProcInfo* getRemoteProcInfo () { return NULL; }
+ unw_accessors_t* accessors() { return NULL; }
+ unw_addr_space_t wrap() { return NULL; }
+#endif
+};
+
+LocalAddressSpace sThisAddress;
+
+inline uintptr_t LocalAddressSpace::getP(pint_t addr)
+{
+#if __LP64__
+ return get64(addr);
+#else
+ return get32(addr);
+#endif
+}
+
+inline uintptr_t LocalAddressSpace::getP(pint_t addr, int &err)
+{
+#if __LP64__
+ return get64(addr);
+#else
+ return get32(addr);
+#endif
+ err = 0;
+}
+
+/* Read a ULEB128 into a 64-bit word. */
+inline uint64_t
+LocalAddressSpace::getULEB128(pint_t& addr, pint_t end)
+{
+ const uint8_t* p = (uint8_t*)addr;
+ const uint8_t* pend = (uint8_t*)end;
+ uint64_t result = 0;
+ int bit = 0;
+ do {
+ uint64_t b;
+
+ if ( p == pend )
+ ABORT("truncated uleb128 expression");
+
+ b = *p & 0x7f;
+
+ if (bit >= 64 || b << bit >> bit != b) {
+ ABORT("malformed uleb128 expression");
+ }
+ else {
+ result |= b << bit;
+ bit += 7;
+ }
+ } while ( *p++ >= 0x80 );
+ addr = (pint_t)p;
+ return result;
+}
+
+/* Read a SLEB128 into a 64-bit word. */
+inline int64_t
+LocalAddressSpace::getSLEB128(pint_t& addr, pint_t end)
+{
+ const uint8_t* p = (uint8_t*)addr;
+ int64_t result = 0;
+ int bit = 0;
+ uint8_t byte;
+ do {
+ byte = *p++;
+ result |= ((byte & 0x7f) << bit);
+ bit += 7;
+ } while (byte & 0x80);
+ // sign extend negative numbers
+ if ( (byte & 0x40) != 0 )
+ result |= (-1LL) << bit;
+ addr = (pint_t)p;
+ return result;
+}
+
+LocalAddressSpace::pint_t
+LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
+{
+ pint_t startAddr = addr;
+ const uint8_t* p = (uint8_t*)addr;
+ pint_t result;
+
+ // first get value
+ switch (encoding & 0x0F) {
+ case DW_EH_PE_ptr:
+ result = getP(addr);
+ p += sizeof(pint_t);
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_uleb128:
+ result = getULEB128(addr, end);
+ break;
+ case DW_EH_PE_udata2:
+ result = get16(addr);
+ p += 2;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_udata4:
+ result = get32(addr);
+ p += 4;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_udata8:
+ result = get64(addr);
+ p += 8;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_sleb128:
+ result = getSLEB128(addr, end);
+ break;
+ case DW_EH_PE_sdata2:
+ result = (int16_t)get16(addr);
+ p += 2;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_sdata4:
+ result = (int32_t)get32(addr);
+ p += 4;
+ addr = (pint_t)p;
+ break;
+ case DW_EH_PE_sdata8:
+ result = get64(addr);
+ p += 8;
+ addr = (pint_t)p;
+ break;
+ default:
+ ABORT("unknown pointer encoding");
+ }
+
+ // then add relative offset
+ switch ( encoding & 0x70 ) {
+ case DW_EH_PE_absptr:
+ // do nothing
+ break;
+ case DW_EH_PE_pcrel:
+ result += startAddr;
+ break;
+ case DW_EH_PE_textrel:
+ ABORT("DW_EH_PE_textrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_datarel:
+ ABORT("DW_EH_PE_datarel pointer encoding not supported");
+ break;
+ case DW_EH_PE_funcrel:
+ ABORT("DW_EH_PE_funcrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_aligned:
+ ABORT("DW_EH_PE_aligned pointer encoding not supported");
+ break;
+ default:
+ ABORT("unknown pointer encoding");
+ break;
+ }
+
+ if ( encoding & DW_EH_PE_indirect )
+ result = getP(result);
+
+ return result;
+}
+
+
+inline bool LocalAddressSpace::findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart)
+{
+#if !defined (SUPPORT_REMOTE_UNWINDING)
+ dyld_unwind_sections info;
+ if ( _dyld_find_unwind_sections((void*)addr, &info) ) {
+ mh = (pint_t)info.mh;
+ dwarfStart = (pint_t)info.dwarf_section;
+ dwarfLen = (pint_t)info.dwarf_section_length;
+ compactStart = (pint_t)info.compact_unwind_section;
+ return true;
+ }
+#else
+ assert("unwinding with a non-remote process not supported.");
+#endif
+ return false;
+}
+
+
+inline bool LocalAddressSpace::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
+{
+ dl_info dyldInfo;
+ if ( dladdr((void*)addr, &dyldInfo) ) {
+ if ( dyldInfo.dli_sname != NULL ) {
+ strlcpy(buf, dyldInfo.dli_sname, bufLen);
+ *offset = (addr - (pint_t)dyldInfo.dli_saddr);
+ return true;
+ }
+ }
+ return false;
+}
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+///
+/// OtherAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
+/// in the another process. The other process can be a different endianness and a different
+/// pointer size and is handled by the P template parameter.
+///
+template <typename P>
+class OtherAddressSpace
+{
+public:
+ OtherAddressSpace (unw_addr_space_t remote_addr_space, void* arg) : fAddrSpace ((unw_addr_space_remote *)remote_addr_space), fArg(arg)
+ {
+ if (fAddrSpace->type != UNW_REMOTE)
+ ABORT("OtherAddressSpace ctor called with non-remote address space.");
+ fRemoteProcInfo = fAddrSpace->ras;
+ }
+
+ typedef typename P::uint_t pint_t;
+ typedef typename P::int_t sint_t;
+
+ int getBytes(pint_t addr, pint_t extent, uint8_t* buf) { return fRemoteProcInfo->getBytes (addr, extent, buf, fArg); }
+ uint8_t get8(pint_t addr) { return fRemoteProcInfo->get8(addr, fArg); }
+ uint16_t get16(pint_t addr) { return fRemoteProcInfo->get16(addr, fArg); }
+ uint32_t get32(pint_t addr) { return fRemoteProcInfo->get32(addr, fArg); }
+ uint64_t get64(pint_t addr) { return fRemoteProcInfo->get64(addr, fArg); }
+ pint_t getP(pint_t addr) { return fRemoteProcInfo->getP(addr, fArg); }
+
+ uint8_t get8(pint_t addr, int& err) { return fRemoteProcInfo->get8(addr, err, fArg); }
+ uint16_t get16(pint_t addr, int& err) { return fRemoteProcInfo->get16(addr, err, fArg); }
+ uint32_t get32(pint_t addr, int& err) { return fRemoteProcInfo->get32(addr, err, fArg); }
+ uint64_t get64(pint_t addr, int& err) { return fRemoteProcInfo->get64(addr, err, fArg); }
+ pint_t getP(pint_t addr, int &err) { return fRemoteProcInfo->getP(addr, err, fArg); }
+
+ uint64_t getULEB128(pint_t& addr, pint_t end) { return fRemoteProcInfo->getULEB128 (addr, end, fArg); }
+ int64_t getSLEB128(pint_t& addr, pint_t end) { return fRemoteProcInfo->getSLEB128 (addr, end, fArg); }
+ pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
+ double getDouble(pint_t addr);
+ v128 getVector(pint_t addr);
+ bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
+ bool findFunctionExtent(pint_t addr, unw_word_t* begin, unw_word_t* end);
+ bool findUnwindSections(pint_t addr, pint_t& mh, pint_t& eh_frame_start, pint_t& eh_frame_len, pint_t& compactStart);
+ RemoteProcInfo* getRemoteProcInfo () { return fRemoteProcInfo; }
+ unw_accessors_t* accessors() { return fRemoteProcInfo->getAccessors(); }
+ unw_addr_space_t wrap() { return (unw_addr_space_t) fAddrSpace; }
+private:
+ void* localCopy(pint_t addr);
+ unw_addr_space_remote *fAddrSpace;
+ RemoteProcInfo* fRemoteProcInfo;
+ void* fArg;
+};
+
+template <typename P>
+typename OtherAddressSpace<P>::pint_t OtherAddressSpace<P>::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
+{
+ pint_t startAddr = addr;
+ pint_t p = addr;
+ pint_t result;
+
+ // first get value
+ switch (encoding & 0x0F) {
+ case DW_EH_PE_ptr:
+ result = fRemoteProcInfo->getP(addr, fArg);
+ p += sizeof(pint_t);
+ addr = p;
+ break;
+ case DW_EH_PE_uleb128:
+ result = fRemoteProcInfo->getULEB128(addr, end, fArg);
+ break;
+ case DW_EH_PE_udata2:
+ result = fRemoteProcInfo->get16(addr, fArg);
+ p += 2;
+ addr = p;
+ break;
+ case DW_EH_PE_udata4:
+ result = fRemoteProcInfo->get32(addr, fArg);
+ p += 4;
+ addr = p;
+ break;
+ case DW_EH_PE_udata8:
+ result = fRemoteProcInfo->get64(addr, fArg);
+ p += 8;
+ addr = p;
+ break;
+ case DW_EH_PE_sleb128:
+ result = fRemoteProcInfo->getSLEB128(addr, end, fArg);
+ break;
+ case DW_EH_PE_sdata2:
+ result = (int16_t)fRemoteProcInfo->get16(addr, fArg);
+ p += 2;
+ addr = p;
+ break;
+ case DW_EH_PE_sdata4:
+ result = (int32_t)fRemoteProcInfo->get32(addr, fArg);
+ p += 4;
+ addr = p;
+ break;
+ case DW_EH_PE_sdata8:
+ result = fRemoteProcInfo->get64(addr, fArg);
+ p += 8;
+ addr = p;
+ break;
+ default:
+ ABORT("unknown pointer encoding");
+ }
+
+ // then add relative offset
+ switch ( encoding & 0x70 ) {
+ case DW_EH_PE_absptr:
+ // do nothing
+ break;
+ case DW_EH_PE_pcrel:
+ result += startAddr;
+ break;
+ case DW_EH_PE_textrel:
+ ABORT("DW_EH_PE_textrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_datarel:
+ ABORT("DW_EH_PE_datarel pointer encoding not supported");
+ break;
+ case DW_EH_PE_funcrel:
+ ABORT("DW_EH_PE_funcrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_aligned:
+ ABORT("DW_EH_PE_aligned pointer encoding not supported");
+ break;
+ default:
+ ABORT("unknown pointer encoding");
+ break;
+ }
+
+ if ( encoding & DW_EH_PE_indirect )
+ result = fRemoteProcInfo->getP(result, fArg);
+
+ return result;
+}
+
+template <typename P>
+double OtherAddressSpace<P>::getDouble(pint_t addr)
+{
+ return fRemoteProcInfo->getDouble(addr, fArg);
+}
+
+template <typename P>
+v128 OtherAddressSpace<P>::getVector(pint_t addr)
+{
+ return fRemoteProcInfo->getVector(addr, fArg);
+}
+
+template <typename P>
+bool OtherAddressSpace<P>::findUnwindSections(pint_t addr, pint_t& mh, pint_t& eh_frame_start, pint_t& eh_frame_len, pint_t& compactStart)
+{
+ compactStart = 0;
+ uint64_t t_mh, t_text_start, t_text_end, t_eh_frame_start, t_eh_frame_len, t_compact_start;
+ if (fRemoteProcInfo->getImageAddresses (addr, t_mh, t_text_start, t_text_end, t_eh_frame_start, t_eh_frame_len, t_compact_start, fArg))
+ {
+ mh = t_mh;
+ eh_frame_start = t_eh_frame_start;
+ eh_frame_len = t_eh_frame_len;
+ compactStart = t_compact_start;
+ return true;
+ }
+ return false;
+}
+
+template <typename P>
+bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
+{
+ return fRemoteProcInfo->findFunctionName (addr, buf, bufLen, offset, fArg);
+}
+
+#endif // SUPPORT_REMOTE_UNWINDING
+
+
+} // namespace lldb_private
+
+
+
+#endif // __ADDRESSSPACE_HPP__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/ArchDefaultUnwinder.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/ArchDefaultUnwinder.hpp
new file mode 100644
index 00000000000..d19d7aea50f
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/ArchDefaultUnwinder.hpp
@@ -0,0 +1,115 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- ArchDefaultUnwinder.hpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Unwind a stack frame using nothing but the default conventions on
+// this architecture.
+
+#ifndef __ARCH_DEFAULT_UNWINDER_HPP
+#define __ARCH_DEFAULT_UNWINDER_HPP
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "RemoteRegisterMap.hpp"
+#include "RemoteProcInfo.hpp"
+
+namespace lldb_private
+{
+
+// As a last ditch attempt to unwind a stack frame, unwind by the
+// architecture's typical conventions. We try compact unwind, eh frame CFI,
+// and then assembly profiling if we have function bounds -- but if we're
+// looking at an address with no function bounds or unwind info, make a best
+// guess at how to get out.
+
+// In practice, this is usually hit when we try to step out of start() in a
+// stripped application binary, we've jumped to 0x0, or we're in jitted code
+// in the heap.
+
+template <typename A, typename R>
+int stepByArchitectureDefault_x86 (A& addressSpace, R& registers,
+ uint64_t pc, int wordsize) {
+ R newRegisters(registers);
+ RemoteRegisterMap *rmap = addressSpace.getRemoteProcInfo()->getRegisterMap();
+ int frame_reg = rmap->unwind_regno_for_frame_pointer();
+ int stack_reg = rmap->unwind_regno_for_stack_pointer();
+ int err;
+
+ /* If the pc is 0x0 either we call'ed 0 (went thorugh a null function
+ pointer) or this is a thread in the middle of being created that has
+ no stack at all.
+ For the call-0x0 case, we know how to unwind that - the pc is at
+ the stack pointer.
+
+ Otherwise follow the usual convention of trusting that RBP/EBP has the
+ start of the stack frame and we can find the caller's pc based on
+ that. */
+
+ uint64_t newpc, newframeptr;
+ newpc = 0;
+ newframeptr = -1;
+ if (pc == 0) {
+ uint64_t oldsp = registers.getRegister(stack_reg);
+ err = 0;
+ if (oldsp != 0) {
+ newpc = addressSpace.getP(registers.getRegister(stack_reg), err);
+ if (err != 0)
+ return UNW_EUNSPEC;
+ newRegisters.setIP (newpc);
+ newRegisters.setRegister (stack_reg, registers.getRegister(stack_reg) +
+ wordsize);
+ }
+ }
+ else {
+ newpc = addressSpace.getP(registers.getRegister(frame_reg) +
+ wordsize, err);
+ if (err != 0)
+ return UNW_EUNSPEC;
+
+ newRegisters.setIP (newpc);
+ newframeptr = addressSpace.getP(registers.getRegister(frame_reg),
+ err);
+ if (err != 0)
+ return UNW_EUNSPEC;
+
+ newRegisters.setRegister (frame_reg, newframeptr);
+ newRegisters.setRegister (stack_reg, registers.getRegister(frame_reg) +
+ (wordsize * 2));
+ }
+ registers = newRegisters;
+ if (newpc == 0 || newframeptr == 0)
+ return UNW_STEP_END;
+ return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int stepByArchitectureDefault (A& addressSpace, Registers_x86_64 &registers,
+ uint64_t pc) {
+ return stepByArchitectureDefault_x86 (addressSpace, registers, pc, 8);
+}
+
+template <typename A>
+int stepByArchitectureDefault (A& addressSpace, Registers_x86& registers,
+ uint64_t pc) {
+ return stepByArchitectureDefault_x86 (addressSpace, registers, pc, 4);
+}
+
+template <typename A>
+int stepByArchitectureDefault (A& addressSpace, Registers_ppc& registers,
+ uint64_t pc) {
+ ABORT("Remote unwinding not supported for ppc.");
+ return UNW_EUNSPEC;
+}
+
+}; // namespace lldb_private
+
+#endif // SUPPORT_REMOTE_UNWINDING
+#endif // __ARCH_DEFAULT_UNWINDER_HPP
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp
new file mode 100644
index 00000000000..1e695d5e4f0
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp
@@ -0,0 +1,147 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- AssemblyInstructions.hpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __ASSEMBLY_INSTRUCTIONS_HPP
+#define __ASSEMBLY_INSTRUCTIONS_HPP
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <map>
+
+#include "libunwind.h"
+#include "AssemblyParser.hpp"
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "RemoteUnwindProfile.h"
+
+namespace lldb_private
+{
+
+// A debug function to dump the contents of an RemoteUnwindProfile to
+// stdout in a human readable form.
+
+template <typename A, typename R>
+void printProfile (A& addressSpace, uint64_t pc, RemoteUnwindProfile* profile, R& registers) {
+ RemoteProcInfo *procinfo = addressSpace.getRemoteProcInfo();
+ RemoteRegisterMap *regmap = procinfo->getRegisterMap();
+
+ procinfo->logDebug ("Print profile: given pc of 0x%llx, profile has range 0x%llx - 0x%llx", pc, profile->fStart, profile->fEnd);
+ procinfo->logDebug ("CFA locations:");
+ std::map<uint64_t, RemoteUnwindProfile::CFALocation>::iterator i;
+ for (i = profile->cfa.begin(); i != profile->cfa.end(); ++i) {
+ procinfo->logDebug (" as of 0x%llx cfa is based off of reg %d (%s) offset %d", i->first, i->second.regno, regmap->unwind_regno_to_name(i->second.regno), i->second.offset);
+ }
+ procinfo->logDebug ("Caller's saved IP is at %d bytes offset from the cfa", (int)profile->returnAddress.value);
+ procinfo->logDebug ("Register saves:");
+ std::map<uint64_t, std::vector<RemoteUnwindProfile::SavedReg> >::iterator j;
+ for (j = profile->saved_registers.begin(); j != profile->saved_registers.end(); ++j) {
+ char *tbuf1, *tbuf2, *tbuf3;
+ asprintf (&tbuf1, " at pc 0x%llx there are %d registers saved ", j->first, (int) j->second.size());
+ std::vector<RemoteUnwindProfile::SavedReg>::iterator k;
+ for (k = j->second.begin(); k != j->second.end(); ++k) {
+ if (k->location == RemoteUnwindProfile::kRegisterOffsetFromCFA) {
+ asprintf (&tbuf2, "[reg %d (%s) is %d bytes from cfa] ", k->regno, regmap->unwind_regno_to_name(k->regno), (int) k->value);
+ int newlen = strlen (tbuf1) + strlen (tbuf2) + 1;
+ tbuf3 = (char *) malloc (newlen);
+ strcpy (tbuf3, tbuf1);
+ strcat (tbuf3, tbuf2);
+ free (tbuf1);
+ free (tbuf2);
+ tbuf1 = tbuf3;
+ }
+ if (k->location == RemoteUnwindProfile::kRegisterIsCFA) {
+ asprintf (&tbuf2, "[reg %d (%s) is the same as the cfa] ", k->regno, regmap->unwind_regno_to_name(k->regno));
+ int newlen = strlen (tbuf1) + strlen (tbuf2) + 1;
+ tbuf3 = (char *) malloc (newlen);
+ strcpy (tbuf3, tbuf1);
+ strcat (tbuf3, tbuf2);
+ free (tbuf1);
+ free (tbuf2);
+ tbuf1 = tbuf3;
+ }
+ }
+ procinfo->logDebug ("%s", tbuf1);
+ free (tbuf1);
+ }
+}
+
+template <typename A, typename R>
+int stepWithAssembly (A& addressSpace, uint64_t pc, RemoteUnwindProfile* profile, R& registers) {
+ R newRegisters(registers);
+ RemoteProcInfo *procinfo = addressSpace.getRemoteProcInfo();
+ if (pc > profile->fEnd)
+ ABORT("stepWithAssembly called with pc not in RemoteUnwindProfile's bounds");
+
+ if (procinfo && (procinfo->getDebugLoggingLevel() & UNW_LOG_LEVEL_DEBUG))
+ printProfile (addressSpace, pc, profile, registers);
+
+ std::map<uint64_t, RemoteUnwindProfile::CFALocation>::iterator i = profile->cfa.lower_bound (pc);
+ if (i == profile->cfa.begin() && i == profile->cfa.end())
+ return UNW_EINVAL;
+ if (i == profile->cfa.end()) {
+ --i;
+ } else {
+ if (i != profile->cfa.begin() && i->first != pc)
+ --i;
+ }
+
+ uint64_t cfa = registers.getRegister (i->second.regno) + i->second.offset;
+
+ std::map<uint64_t, std::vector<RemoteUnwindProfile::SavedReg> >::iterator j;
+
+ for (j = profile->saved_registers.begin(); j != profile->saved_registers.end() && j->first <= pc; ++j) {
+ std::vector<RemoteUnwindProfile::SavedReg>::iterator k = j->second.begin();
+ for (; k != j->second.end(); ++k) {
+ RemoteUnwindProfile::SavedReg sr = *k;
+ if (sr.type == RemoteUnwindProfile::kGeneralPurposeRegister) {
+ uint64_t result;
+ int err = 0;
+ switch (sr.location) {
+ case RemoteUnwindProfile::kRegisterOffsetFromCFA:
+ result = addressSpace.getP(cfa + sr.value, err);
+ break;
+ case RemoteUnwindProfile::kRegisterIsCFA:
+ result = cfa;
+ break;
+ default:
+ ABORT("Unknown saved register location in stepWithAssembly.");
+ }
+ // If we failed to read remote memory, stop unwinding.
+ if (err)
+ return UNW_STEP_END;
+ newRegisters.setRegister (sr.regno, result);
+ }
+ }
+ }
+ newRegisters.setSP(cfa);
+ uint64_t ip = addressSpace.getP(cfa + profile->returnAddress.value);
+ if (ip == 0)
+ return UNW_STEP_END;
+ newRegisters.setIP(ip);
+ registers = newRegisters;
+ return UNW_STEP_SUCCESS;
+}
+
+}; // namespace lldb_private
+
+#endif // SUPPORT_REMOTE_UNWINDING
+#endif //ASSEMBLY_INSTRUCTIONS_HPP
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyParser.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyParser.hpp
new file mode 100644
index 00000000000..b34f93f50c6
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyParser.hpp
@@ -0,0 +1,409 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- AssemblyParser.hpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Disassemble the prologue instructions in functions, create a profile
+// of stack movements and register saves performed therein.
+
+#ifndef __ASSEMBLY_PARSER_HPP
+#define __ASSEMBLY_PARSER_HPP
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <map>
+#include <vector>
+
+#include "libunwind.h"
+#include "RemoteProcInfo.hpp"
+#include "Registers.hpp"
+#include "FileAbstraction.hpp"
+#include "AddressSpace.hpp"
+#include "RemoteUnwindProfile.h"
+
+namespace lldb_private
+{
+
+// Analyze the instructions in an x86_64/i386 function prologue, fill out an RemoteUnwindProfile.
+
+class AssemblyParse_x86 {
+public:
+ AssemblyParse_x86 (RemoteProcInfo& procinfo, unw_accessors_t *acc, unw_addr_space_t as, void *arg) : fArg(arg), fAccessors(acc), fAs(as), fRemoteProcInfo(procinfo) {
+ fRegisterMap = fRemoteProcInfo.getRegisterMap();
+ if (fRemoteProcInfo.getTargetArch() == UNW_TARGET_X86_64) {
+ fStackPointerRegnum = UNW_X86_64_RSP;
+ fFramePointerRegnum = UNW_X86_64_RBP;
+ fWordSize = 8;
+ } else {
+ fStackPointerRegnum = UNW_X86_ESP;
+ fFramePointerRegnum = UNW_X86_EBP;
+ fWordSize = 4;
+ }
+ }
+
+ uint32_t extract_4_LE (uint8_t *b) {
+ uint32_t v = 0;
+ for (int i = 3; i >= 0; i--)
+ v = (v << 8) | b[i];
+ return v;
+ }
+
+ 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 *rbp_offset);
+ bool ret_pattern_p ();
+ bool profileFunction (uint64_t start, uint64_t end, RemoteUnwindProfile& profile);
+
+private:
+
+ void *fArg;
+ uint8_t* fCurInsnByteBuf;
+ int fCurInsnSize;
+ RemoteProcInfo& fRemoteProcInfo;
+ RemoteRegisterMap *fRegisterMap;
+ unw_accessors_t *fAccessors;
+ unw_addr_space_t fAs;
+ int fWordSize;
+ int fStackPointerRegnum;
+ int fFramePointerRegnum;
+};
+
+// 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 = fCurInsnByteBuf;
+ 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 = fCurInsnByteBuf;
+ 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 = fCurInsnByteBuf;
+ if (fWordSize == 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 = fCurInsnByteBuf;
+ if (fWordSize == 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_LE (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 = fCurInsnByteBuf;
+ int regno_prefix_bit = 0;
+ // If we have a rex prefix byte, check to see if a B bit is set
+ if (fWordSize == 8 && *p == 0x41) {
+ regno_prefix_bit = 1 << 3;
+ p++;
+ }
+ if (*p >= 0x50 && *p <= 0x57) {
+ int r = (*p - 0x50) | regno_prefix_bit;
+ if (fRegisterMap->machine_regno_to_unwind_regno (r, *regno) == true) {
+ 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 = fCurInsnByteBuf;
+ int src_reg_prefix_bit = 0;
+ int target_reg_prefix_bit = 0;
+
+ if (fWordSize == 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_LE (p + 2);
+ if (offset > 0)
+ return false;
+
+ int savedreg = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit;
+ if (fRegisterMap->machine_regno_to_unwind_regno (savedreg, *regno) == true) {
+ *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 = fCurInsnByteBuf;
+ if (*p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3)
+ return true;
+ return false;
+}
+
+bool AssemblyParse_x86::profileFunction (uint64_t start, uint64_t end, RemoteUnwindProfile& profile) {
+ if (start == -1 || end == 0)
+ return false;
+
+ profile.fStart = start;
+ profile.fEnd = end;
+ profile.fRegSizes[RemoteUnwindProfile::kGeneralPurposeRegister] = fWordSize;
+ profile.fRegSizes[RemoteUnwindProfile::kFloatingPointRegister] = 8;
+ profile.fRegSizes[RemoteUnwindProfile::kVectorRegister] = 16;
+
+ // On function entry, the CFA is rsp+fWordSize
+
+ RemoteUnwindProfile::CFALocation initial_cfaloc;
+ initial_cfaloc.regno = fStackPointerRegnum;
+ initial_cfaloc.offset = fWordSize;
+ profile.cfa[start] = initial_cfaloc;
+
+ // The return address is at CFA - fWordSize
+ // CFA doesn't change value during the lifetime of the function (hence "C")
+ // so the returnAddress is the same for the duration of the function.
+
+ profile.returnAddress.regno = 0;
+ profile.returnAddress.location = RemoteUnwindProfile::kRegisterOffsetFromCFA;
+ profile.returnAddress.value = -fWordSize;
+ profile.returnAddress.adj = 0;
+ profile.returnAddress.type = RemoteUnwindProfile::kGeneralPurposeRegister;
+
+ // The caller's rsp has the same value as the CFA at all points during
+ // this function's lifetime.
+
+ RemoteUnwindProfile::SavedReg rsp_loc;
+ rsp_loc.regno = fStackPointerRegnum;
+ rsp_loc.location = RemoteUnwindProfile::kRegisterIsCFA;
+ rsp_loc.value = 0;
+ rsp_loc.adj = 0;
+ rsp_loc.type = RemoteUnwindProfile::kGeneralPurposeRegister;
+ profile.saved_registers[start].push_back(rsp_loc);
+ profile.fRegistersSaved[fStackPointerRegnum] = 1;
+
+ int non_prologue_insn_count = 0;
+ int insn_count = 0;
+ uint64_t cur_addr = start;
+ uint64_t first_insn_past_prologue = start;
+ int push_rbp_seen = 0;
+ int current_cfa_register = fStackPointerRegnum;
+ int sp_adjustments = 0;
+
+ while (cur_addr < end && non_prologue_insn_count < 10)
+ {
+ int offset, regno;
+ uint64_t next_addr;
+ insn_count++;
+ int is_prologue_insn = 0;
+
+ if (fAccessors->instruction_length (fAs, cur_addr, &fCurInsnSize, fArg) != 0) {
+ /* An error parsing the instruction; stop scanning. */
+ break;
+ }
+ fCurInsnByteBuf = (uint8_t *) malloc (fCurInsnSize);
+ if (fRemoteProcInfo.getBytes (cur_addr, fCurInsnSize, fCurInsnByteBuf, fArg) == 0)
+ return false;
+ next_addr = cur_addr + fCurInsnSize;
+
+ // start () opens with a 'push $0x0' which is in the saved ip slot on the stack -
+ // so we know to stop backtracing here. We need to ignore this instruction.
+ if (push_0_pattern_p () && push_rbp_seen == 0 && insn_count == 1)
+ {
+ cur_addr = next_addr;
+ first_insn_past_prologue = next_addr;
+ continue;
+ }
+
+ if (push_rbp_pattern_p () && push_rbp_seen == 0)
+ {
+ if (current_cfa_register == fStackPointerRegnum) {
+ sp_adjustments -= fWordSize;
+ RemoteUnwindProfile::CFALocation cfaloc;
+ cfaloc.regno = fStackPointerRegnum;
+ cfaloc.offset = abs (sp_adjustments - fWordSize);
+ profile.cfa[next_addr] = cfaloc;
+ }
+
+ RemoteUnwindProfile::SavedReg sreg;
+ sreg.regno = fFramePointerRegnum;
+ sreg.location = RemoteUnwindProfile::kRegisterOffsetFromCFA;
+ sreg.value = sp_adjustments - fWordSize;
+ sreg.adj = 0;
+ sreg.type = RemoteUnwindProfile::kGeneralPurposeRegister;
+ profile.saved_registers[next_addr].push_back(sreg);
+
+ push_rbp_seen = 1;
+ profile.fRegistersSaved[fFramePointerRegnum] = 1;
+ is_prologue_insn = 1;
+ goto next_iteration;
+ }
+ if (mov_rsp_rbp_pattern_p ()) {
+ RemoteUnwindProfile::CFALocation cfaloc;
+ cfaloc.regno = fFramePointerRegnum;
+ cfaloc.offset = abs (sp_adjustments - fWordSize);
+ profile.cfa[next_addr] = cfaloc;
+ current_cfa_register = fFramePointerRegnum;
+ is_prologue_insn = 1;
+ goto next_iteration;
+ }
+ if (ret_pattern_p ()) {
+ break;
+ }
+ if (sub_rsp_pattern_p (&offset)) {
+ sp_adjustments -= offset;
+ if (current_cfa_register == fStackPointerRegnum) {
+ RemoteUnwindProfile::CFALocation cfaloc;
+ cfaloc.regno = fStackPointerRegnum;
+ cfaloc.offset = abs (sp_adjustments - fWordSize);
+ profile.cfa[next_addr] = cfaloc;
+ }
+ is_prologue_insn = 1;
+ }
+ if (push_reg_p (&regno)) {
+ sp_adjustments -= fWordSize;
+ if (current_cfa_register == fStackPointerRegnum) {
+ RemoteUnwindProfile::CFALocation cfaloc;
+ cfaloc.regno = fStackPointerRegnum;
+ cfaloc.offset = abs (sp_adjustments - fWordSize);
+ profile.cfa[next_addr] = cfaloc;
+ is_prologue_insn = 1;
+ }
+ if (fRegisterMap->nonvolatile_reg_p (regno) && profile.fRegistersSaved[regno] == 0) {
+ RemoteUnwindProfile::SavedReg sreg;
+ sreg.regno = regno;
+ sreg.location = RemoteUnwindProfile::kRegisterOffsetFromCFA;
+ sreg.value = sp_adjustments - fWordSize;
+ sreg.adj = 0;
+ sreg.type = RemoteUnwindProfile::kGeneralPurposeRegister;
+ profile.saved_registers[next_addr].push_back(sreg);
+ profile.fRegistersSaved[regno] = 1;
+ is_prologue_insn = 1;
+ }
+ }
+ if (mov_reg_to_local_stack_frame_p (&regno, &offset)
+ && fRegisterMap->nonvolatile_reg_p (regno)
+ && profile.fRegistersSaved[regno] == 0) {
+ RemoteUnwindProfile::SavedReg sreg;
+ sreg.regno = regno;
+ sreg.location = RemoteUnwindProfile::kRegisterOffsetFromCFA;
+ sreg.value = offset - fWordSize;
+ sreg.adj = 0;
+ sreg.type = RemoteUnwindProfile::kGeneralPurposeRegister;
+ profile.saved_registers[next_addr].push_back(sreg);
+ profile.fRegistersSaved[regno] = 1;
+ is_prologue_insn = 1;
+ }
+next_iteration:
+ if (is_prologue_insn) {
+ first_insn_past_prologue = next_addr;
+ non_prologue_insn_count = 0;
+ }
+ cur_addr = next_addr;
+ non_prologue_insn_count++;
+ }
+ profile.fFirstInsnPastPrologue = first_insn_past_prologue;
+ return true;
+}
+
+
+
+
+bool AssemblyParse (RemoteProcInfo *procinfo, unw_accessors_t *acc, unw_addr_space_t as, uint64_t start, uint64_t end, RemoteUnwindProfile &profile, void *arg) {
+ if (procinfo->getTargetArch() == UNW_TARGET_X86_64 || procinfo->getTargetArch() == UNW_TARGET_I386) {
+ AssemblyParse_x86 parser(*procinfo, acc, as, arg);
+ return parser.profileFunction (start, end, profile);
+ } else {
+ ABORT("Only x86_64 and i386 assembly parsing supported at this time");
+ return false;
+ }
+}
+
+}; // namespace lldb_private
+
+#endif // SUPPORT_REMOTE_UNWINDING
+#endif //ASSEMBLY_PARSER_HPP
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp
new file mode 100644
index 00000000000..dda2308ada6
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/CompactUnwinder.hpp
@@ -0,0 +1,1019 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- CompactUnwinder.hpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//
+// C++ interface to lower levels of libuwind
+//
+
+#ifndef __COMPACT_UNWINDER_HPP__
+#define __COMPACT_UNWINDER_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <libunwind.h>
+#include <mach-o/compact_unwind_encoding.h>
+
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+
+
+
+#define EXTRACT_BITS(value, mask) \
+ ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
+
+#define SUPPORT_OLD_BINARIES 0
+
+namespace lldb_private {
+
+
+
+///
+/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka unwind) by
+/// modifying a Registers_x86 register set
+///
+template <typename A>
+class CompactUnwinder_x86
+{
+public:
+
+ static int stepWithCompactEncoding(compact_unwind_encoding_t info, uint32_t functionStart, A& addressSpace, Registers_x86& registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static void frameUnwind(A& addressSpace, Registers_x86& registers);
+ static void framelessUnwind(A& addressSpace, typename A::pint_t returnAddressLocation, Registers_x86& registers);
+ static int stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers);
+ static int stepWithCompactEncodingFrameless(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers, bool indirectStackSize);
+#if SUPPORT_OLD_BINARIES
+ static int stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers);
+#endif
+};
+
+
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers)
+{
+ //fprintf(stderr, "stepWithCompactEncoding(0x%08X)\n", compactEncoding);
+ switch ( compactEncoding & UNWIND_X86_MODE_MASK ) {
+#if SUPPORT_OLD_BINARIES
+ case UNWIND_X86_MODE_COMPATIBILITY:
+ return stepWithCompactEncodingCompat(compactEncoding, functionStart, addressSpace, registers);
+#endif
+ case UNWIND_X86_MODE_EBP_FRAME:
+ return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart, addressSpace, registers);
+ case UNWIND_X86_MODE_STACK_IMMD:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, false);
+ case UNWIND_X86_MODE_STACK_IND:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, true);
+ }
+ ABORT("invalid compact unwind encoding");
+}
+
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+ A& addressSpace, Registers_x86& registers)
+{
+ uint32_t savedRegistersOffset = EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations = EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);
+
+ uint64_t savedRegisters = registers.getEBP() - 4*savedRegistersOffset;
+ for (int i=0; i < 5; ++i) {
+ switch (savedRegistersLocations & 0x7) {
+ case UNWIND_X86_REG_NONE:
+ // no register saved in this slot
+ break;
+ case UNWIND_X86_REG_EBX:
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ECX:
+ registers.setECX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDX:
+ registers.setEDX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDI:
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ESI:
+ registers.setESI(addressSpace.get32(savedRegisters));
+ break;
+ default:
+ DEBUG_MESSAGE("bad register for EBP frame, encoding=%08X for function starting at 0x%X\n", compactEncoding, functionStart);
+ ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 4;
+ savedRegistersLocations = (savedRegistersLocations >> 3);
+ }
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(compact_unwind_encoding_t encoding, uint32_t functionStart,
+ A& addressSpace, Registers_x86& registers, bool indirectStackSize)
+{
+ uint32_t stackSizeEncoded = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
+ uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
+ uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
+ uint32_t stackSize = stackSizeEncoded*4;
+ if ( indirectStackSize ) {
+ // stack size is encoded in subl $xxx,%esp instruction
+ uint32_t subl = addressSpace.get32(functionStart+stackSizeEncoded);
+ stackSize = subl + 4*stackAdjust;
+ }
+ // decompress permutation
+ int permunreg[6];
+ switch ( regCount ) {
+ case 6:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation/60;
+ permutation -= (permunreg[0]*60);
+ permunreg[1] = permutation/12;
+ permutation -= (permunreg[1]*12);
+ permunreg[2] = permutation/3;
+ permutation -= (permunreg[2]*3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation/20;
+ permutation -= (permunreg[0]*20);
+ permunreg[1] = permutation/4;
+ permutation -= (permunreg[1]*4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation/5;
+ permutation -= (permunreg[0]*5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+ // re-number registers back to standard numbers
+ int registersSaved[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (uint32_t i=0; i < regCount; ++i) {
+ int renum = 0;
+ for (int u=1; u < 7; ++u) {
+ if ( !used[u] ) {
+ if ( renum == permunreg[i] ) {
+ registersSaved[i] = u;
+ used[u] = true;
+ break;
+ }
+ ++renum;
+ }
+ }
+ }
+ uint64_t savedRegisters = registers.getSP() + stackSize - 4 - 4*regCount;
+ for (uint32_t i=0; i < regCount; ++i) {
+ switch ( registersSaved[i] ) {
+ case UNWIND_X86_REG_EBX:
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ECX:
+ registers.setECX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDX:
+ registers.setEDX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDI:
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ESI:
+ registers.setESI(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EBP:
+ registers.setEBP(addressSpace.get32(savedRegisters));
+ break;
+ default:
+ DEBUG_MESSAGE("bad register for frameless, encoding=%08X for function starting at 0x%X\n", encoding, functionStart);
+ ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 4;
+ }
+ framelessUnwind(addressSpace, savedRegisters, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+
+#if SUPPORT_OLD_BINARIES
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint32_t functionStart, A& addressSpace, Registers_x86& registers)
+{
+ //fprintf(stderr, "stepWithCompactEncoding(0x%08X)\n", compactEncoding);
+ typename A::pint_t savedRegisters;
+ uint32_t stackValue = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_SIZE);
+ uint32_t stackSize;
+ uint32_t stackAdjust;
+ switch (compactEncoding & UNWIND_X86_CASE_MASK ) {
+ case UNWIND_X86_UNWIND_INFO_UNSPECIFIED:
+ return UNW_ENOINFO;
+
+ case UNWIND_X86_EBP_FRAME_NO_REGS:
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EBX:
+ savedRegisters = registers.getEBP() - 4;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_ESI:
+ savedRegisters = registers.getEBP() - 4;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EDI:
+ savedRegisters = registers.getEBP() - 4;
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EBX_ESI:
+ savedRegisters = registers.getEBP() - 8;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_ESI_EDI:
+ savedRegisters = registers.getEBP() - 8;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EBX_ESI_EDI:
+ savedRegisters = registers.getEBP() - 12;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_EBP_FRAME_EBX_EDI:
+ savedRegisters = registers.getEBP() - 8;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_NO_REGS:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*0;
+ framelessUnwind(addressSpace, savedRegisters+4*0, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EBX:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_ESI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EDI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EBX_ESI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*2;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ framelessUnwind(addressSpace, savedRegisters+4*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_ESI_EDI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*2;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ framelessUnwind(addressSpace, savedRegisters+4*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_ESI_EDI_EBP:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*3;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ registers.setEBP(addressSpace.get32(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+4*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EBX_ESI_EDI:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*3;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+4*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IMM_STK_EBX_ESI_EDI_EBP:
+ stackSize = stackValue * 4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*4;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ registers.setEBP(addressSpace.get32(savedRegisters+12));
+ framelessUnwind(addressSpace, savedRegisters+4*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_NO_REGS:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*0;
+ framelessUnwind(addressSpace, savedRegisters+4*0, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_EBX:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_ESI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_EDI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*1;
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ return UNW_STEP_SUCCESS;
+ framelessUnwind(addressSpace, savedRegisters+4*1, registers);
+
+ case UNWIND_X86_IND_STK_EBX_ESI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*2;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ framelessUnwind(addressSpace, savedRegisters+4*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_ESI_EDI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*2;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ framelessUnwind(addressSpace, savedRegisters+4*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_ESI_EDI_EBP:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*3;
+ registers.setESI(addressSpace.get32(savedRegisters));
+ registers.setEDI(addressSpace.get32(savedRegisters+4));
+ registers.setEBP(addressSpace.get32(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+4*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_EBX_ESI_EDI:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*3;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+4*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_IND_STK_EBX_ESI_EDI_EBP:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_STACK_ADJUST);
+ stackSize += stackAdjust*4;
+ savedRegisters = registers.getSP() + stackSize - 4 - 4*4;
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ registers.setESI(addressSpace.get32(savedRegisters+4));
+ registers.setEDI(addressSpace.get32(savedRegisters+8));
+ registers.setEBP(addressSpace.get32(savedRegisters+12));
+ framelessUnwind(addressSpace, savedRegisters+4*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ default:
+ DEBUG_MESSAGE("unknown compact unwind encoding %08X for function starting at 0x%X\n",
+ compactEncoding & UNWIND_X86_CASE_MASK, functionStart);
+ ABORT("unknown compact unwind encoding");
+ }
+ return UNW_EINVAL;
+}
+#endif // SUPPORT_OLD_BINARIES
+
+
+
+template <typename A>
+void CompactUnwinder_x86<A>::frameUnwind(A& addressSpace, Registers_x86& registers)
+{
+ typename A::pint_t bp = registers.getEBP();
+ // ebp points to old ebp
+ registers.setEBP(addressSpace.get32(bp));
+ // old esp is ebp less saved ebp and return address
+ registers.setSP(bp+8);
+ // pop return address into eip
+ registers.setIP(addressSpace.get32(bp+4));
+}
+
+template <typename A>
+void CompactUnwinder_x86<A>::framelessUnwind(A& addressSpace, typename A::pint_t returnAddressLocation, Registers_x86& registers)
+{
+ // return address is on stack after last saved register
+ registers.setIP(addressSpace.get32(returnAddressLocation));
+ // old esp is before return address
+ registers.setSP(returnAddressLocation+4);
+}
+
+
+
+
+
+///
+/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka unwind) by
+/// modifying a Registers_x86_64 register set
+///
+template <typename A>
+class CompactUnwinder_x86_64
+{
+public:
+
+ static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static void frameUnwind(A& addressSpace, Registers_x86_64& registers);
+ static void framelessUnwind(A& addressSpace, uint64_t returnAddressLocation, Registers_x86_64& registers);
+ static int stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers);
+ static int stepWithCompactEncodingFrameless(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers, bool indirectStackSize);
+#if SUPPORT_OLD_BINARIES
+ static int stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers);
+#endif
+};
+
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers)
+{
+ //fprintf(stderr, "stepWithCompactEncoding(0x%08X)\n", compactEncoding);
+ switch ( compactEncoding & UNWIND_X86_64_MODE_MASK ) {
+#if SUPPORT_OLD_BINARIES
+ case UNWIND_X86_64_MODE_COMPATIBILITY:
+ return stepWithCompactEncodingCompat(compactEncoding, functionStart, addressSpace, registers);
+#endif
+ case UNWIND_X86_64_MODE_RBP_FRAME:
+ return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart, addressSpace, registers);
+ case UNWIND_X86_64_MODE_STACK_IMMD:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, false);
+ case UNWIND_X86_64_MODE_STACK_IND:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart, addressSpace, registers, true);
+ }
+ ABORT("invalid compact unwind encoding");
+}
+
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A& addressSpace, Registers_x86_64& registers)
+{
+ uint32_t savedRegistersOffset = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
+
+ uint64_t savedRegisters = registers.getRBP() - 8*savedRegistersOffset;
+ for (int i=0; i < 5; ++i) {
+ int readerr = 0;
+ switch (savedRegistersLocations & 0x7) {
+ case UNWIND_X86_64_REG_NONE:
+ // no register saved in this slot
+ break;
+ case UNWIND_X86_64_REG_RBX:
+ registers.setRBX(addressSpace.get64(savedRegisters, readerr));
+ break;
+ case UNWIND_X86_64_REG_R12:
+ registers.setR12(addressSpace.get64(savedRegisters, readerr));
+ break;
+ case UNWIND_X86_64_REG_R13:
+ registers.setR13(addressSpace.get64(savedRegisters, readerr));
+ break;
+ case UNWIND_X86_64_REG_R14:
+ registers.setR14(addressSpace.get64(savedRegisters, readerr));
+ break;
+ case UNWIND_X86_64_REG_R15:
+ registers.setR15(addressSpace.get64(savedRegisters, readerr));
+ break;
+ default:
+ DEBUG_MESSAGE("bad register for RBP frame, encoding=%08X for function starting at 0x%llX\n", compactEncoding, functionStart);
+ ABORT("invalid compact unwind encoding");
+ }
+ // Error reading memory while doing a remote unwind?
+ if (readerr)
+ return UNW_STEP_END;
+
+ savedRegisters += 8;
+ savedRegistersLocations = (savedRegistersLocations >> 3);
+ }
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(compact_unwind_encoding_t encoding, uint64_t functionStart,
+ A& addressSpace, Registers_x86_64& registers, bool indirectStackSize)
+{
+ uint32_t stackSizeEncoded = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+ uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
+ uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
+ uint32_t stackSize = stackSizeEncoded*8;
+ if ( indirectStackSize ) {
+ // stack size is encoded in subl $xxx,%esp instruction
+ uint32_t subl = addressSpace.get32(functionStart+stackSizeEncoded);
+ stackSize = subl + 8*stackAdjust;
+ }
+ // decompress permutation
+ int permunreg[6];
+ switch ( regCount ) {
+ case 6:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation/60;
+ permutation -= (permunreg[0]*60);
+ permunreg[1] = permutation/12;
+ permutation -= (permunreg[1]*12);
+ permunreg[2] = permutation/3;
+ permutation -= (permunreg[2]*3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation/20;
+ permutation -= (permunreg[0]*20);
+ permunreg[1] = permutation/4;
+ permutation -= (permunreg[1]*4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation/5;
+ permutation -= (permunreg[0]*5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+ // re-number registers back to standard numbers
+ int registersSaved[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (uint32_t i=0; i < regCount; ++i) {
+ int renum = 0;
+ for (int u=1; u < 7; ++u) {
+ if ( !used[u] ) {
+ if ( renum == permunreg[i] ) {
+ registersSaved[i] = u;
+ used[u] = true;
+ break;
+ }
+ ++renum;
+ }
+ }
+ }
+ uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8*regCount;
+ for (uint32_t i=0; i < regCount; ++i) {
+ switch ( registersSaved[i] ) {
+ case UNWIND_X86_64_REG_RBX:
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R12:
+ registers.setR12(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R13:
+ registers.setR13(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R14:
+ registers.setR14(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R15:
+ registers.setR15(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_RBP:
+ registers.setRBP(addressSpace.get64(savedRegisters));
+ break;
+ default:
+ DEBUG_MESSAGE("bad register for frameless, encoding=%08X for function starting at 0x%llX\n", encoding, functionStart);
+ ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 8;
+ }
+ framelessUnwind(addressSpace, savedRegisters, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+#if SUPPORT_OLD_BINARIES
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingCompat(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A& addressSpace, Registers_x86_64& registers)
+{
+ uint64_t savedRegisters;
+ uint32_t stackValue = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_SIZE);
+ uint64_t stackSize;
+ uint32_t stackAdjust;
+
+ switch (compactEncoding & UNWIND_X86_64_CASE_MASK ) {
+ case UNWIND_X86_64_UNWIND_INFO_UNSPECIFIED:
+ return UNW_ENOINFO;
+
+ case UNWIND_X86_64_RBP_FRAME_NO_REGS:
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX:
+ savedRegisters = registers.getRBP() - 8*1;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX_R12:
+ savedRegisters = registers.getRBP() - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX_R12_R13:
+ savedRegisters = registers.getRBP() - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX_R12_R13_R14:
+ savedRegisters = registers.getRBP() - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_RBP_FRAME_RBX_R12_R13_R14_R15:
+ savedRegisters = registers.getRBP() - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ registers.setR15(addressSpace.get64(savedRegisters+32));
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_NO_REGS:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*0;
+ framelessUnwind(addressSpace, savedRegisters+8*0, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*1;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+8*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_R12:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+8*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+8*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_R12_R13:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ framelessUnwind(addressSpace, savedRegisters+8*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_R12_R13_R14:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ framelessUnwind(addressSpace, savedRegisters+8*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_R12_R13_R14_R15:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ registers.setR15(addressSpace.get64(savedRegisters+32));
+ framelessUnwind(addressSpace, savedRegisters+8*5, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP_R12_R13_R14_R15:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*6;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ registers.setR14(addressSpace.get64(savedRegisters+32));
+ registers.setR15(addressSpace.get64(savedRegisters+40));
+ framelessUnwind(addressSpace, savedRegisters+8*6, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP_R12:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ framelessUnwind(addressSpace, savedRegisters+8*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP_R12_R13:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ framelessUnwind(addressSpace, savedRegisters+8*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IMM_STK_RBX_RBP_R12_R13_R14:
+ stackSize = stackValue * 8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ registers.setR14(addressSpace.get64(savedRegisters+32));
+ framelessUnwind(addressSpace, savedRegisters+8*5, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_NO_REGS:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*0;
+ framelessUnwind(addressSpace, savedRegisters+8*0, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*1;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ framelessUnwind(addressSpace, savedRegisters+8*1, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_R12:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+8*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*2;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ framelessUnwind(addressSpace, savedRegisters+8*2, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_R12_R13:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ framelessUnwind(addressSpace, savedRegisters+8*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_R12_R13_R14:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ framelessUnwind(addressSpace, savedRegisters+8*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_R12_R13_R14_R15:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setR12(addressSpace.get64(savedRegisters+8));
+ registers.setR13(addressSpace.get64(savedRegisters+16));
+ registers.setR14(addressSpace.get64(savedRegisters+24));
+ registers.setR15(addressSpace.get64(savedRegisters+32));
+ framelessUnwind(addressSpace, savedRegisters+8*5, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP_R12_R13_R14_R15:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*6;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ registers.setR14(addressSpace.get64(savedRegisters+32));
+ registers.setR15(addressSpace.get64(savedRegisters+40));
+ framelessUnwind(addressSpace, savedRegisters+8*6, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP_R12:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*3;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ framelessUnwind(addressSpace, savedRegisters+8*3, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP_R12_R13:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*4;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ framelessUnwind(addressSpace, savedRegisters+8*4, registers);
+ return UNW_STEP_SUCCESS;
+
+ case UNWIND_X86_64_IND_STK_RBX_RBP_R12_R13_R14:
+ stackSize = addressSpace.get32(functionStart+stackValue);
+ stackAdjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_STACK_ADJUST);
+ stackSize += stackAdjust*8;
+ savedRegisters = registers.getSP() + stackSize - 8 - 8*5;
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ registers.setRBP(addressSpace.get64(savedRegisters+8));
+ registers.setR12(addressSpace.get64(savedRegisters+16));
+ registers.setR13(addressSpace.get64(savedRegisters+24));
+ registers.setR14(addressSpace.get64(savedRegisters+32));
+ framelessUnwind(addressSpace, savedRegisters+8*5, registers);
+ return UNW_STEP_SUCCESS;
+
+ default:
+ DEBUG_MESSAGE("unknown compact unwind encoding %08X for function starting at 0x%llX\n",
+ compactEncoding & UNWIND_X86_64_CASE_MASK, functionStart);
+ ABORT("unknown compact unwind encoding");
+ }
+ return UNW_EINVAL;
+}
+#endif // SUPPORT_OLD_BINARIES
+
+
+template <typename A>
+void CompactUnwinder_x86_64<A>::frameUnwind(A& addressSpace, Registers_x86_64& registers)
+{
+ uint64_t rbp = registers.getRBP();
+ // ebp points to old ebp
+ registers.setRBP(addressSpace.get64(rbp));
+ // old esp is ebp less saved ebp and return address
+ registers.setSP(rbp+16);
+ // pop return address into eip
+ registers.setIP(addressSpace.get64(rbp+8));
+}
+
+template <typename A>
+void CompactUnwinder_x86_64<A>::framelessUnwind(A& addressSpace, uint64_t returnAddressLocation, Registers_x86_64& registers)
+{
+ // return address is on stack after last saved register
+ registers.setIP(addressSpace.get64(returnAddressLocation));
+ // old esp is before return address
+ registers.setSP(returnAddressLocation+8);
+}
+
+
+}; // namespace lldb_private
+
+
+
+#endif // __COMPACT_UNWINDER_HPP__
+
+
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/DwarfInstructions.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/DwarfInstructions.hpp
new file mode 100644
index 00000000000..589c30b50b9
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/DwarfInstructions.hpp
@@ -0,0 +1,1686 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- DwarfInstructions.hpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//
+// processor specific parsing of dwarf unwind instructions
+//
+
+#ifndef __DWARF_INSTRUCTIONS_HPP__
+#define __DWARF_INSTRUCTIONS_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <algorithm>
+#include <vector>
+
+#include <libunwind.h>
+#include <mach-o/compact_unwind_encoding.h>
+
+#include "dwarf2.h"
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "DwarfParser.hpp"
+#include "InternalMacros.h"
+//#include "CompactUnwinder.hpp"
+
+#define EXTRACT_BITS(value, mask) \
+ ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
+
+#define CFI_INVALID_ADDRESS ((pint_t)(-1))
+
+namespace lldb_private {
+
+///
+/// Used by linker when parsing __eh_frame section
+///
+template <typename A>
+struct CFI_Reference {
+ typedef typename A::pint_t pint_t;
+ uint8_t encodingOfTargetAddress;
+ uint32_t offsetInCFI;
+ pint_t targetAddress;
+};
+template <typename A>
+struct CFI_Atom_Info {
+ typedef typename A::pint_t pint_t;
+ pint_t address;
+ uint32_t size;
+ bool isCIE;
+ union {
+ struct {
+ CFI_Reference<A> function;
+ CFI_Reference<A> cie;
+ CFI_Reference<A> lsda;
+ uint32_t compactUnwindInfo;
+ } fdeInfo;
+ struct {
+ CFI_Reference<A> personality;
+ } cieInfo;
+ } u;
+};
+
+typedef void (*WarnFunc)(void* ref, uint64_t funcAddr, const char* msg);
+
+///
+/// DwarfInstructions maps abtract dwarf unwind instructions to a particular architecture
+///
+template <typename A, typename R>
+class DwarfInstructions
+{
+public:
+ typedef typename A::pint_t pint_t;
+ typedef typename A::sint_t sint_t;
+
+ static const char* parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
+ CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn);
+
+
+ static compact_unwind_encoding_t createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart,
+ pint_t* lsda, pint_t* personality,
+ char warningBuffer[1024]);
+
+ static int stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers);
+
+private:
+
+ enum {
+ DW_X86_64_RET_ADDR = 16
+ };
+
+ enum {
+ DW_X86_RET_ADDR = 8
+ };
+
+ static pint_t evaluateExpression(pint_t expression, A& addressSpace, const R& registers, pint_t initialStackValue);
+ static pint_t getSavedRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg);
+ static double getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg);
+ static v128 getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg);
+
+ // x86 specific variants
+ static int lastRestoreReg(const Registers_x86&);
+ static bool isReturnAddressRegister(int regNum, const Registers_x86&);
+ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_x86&);
+
+ static uint32_t getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure);
+ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86&);
+ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_x86&, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024]);
+
+ // x86_64 specific variants
+ static int lastRestoreReg(const Registers_x86_64&);
+ static bool isReturnAddressRegister(int regNum, const Registers_x86_64&);
+ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_x86_64&);
+
+ static uint32_t getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure);
+ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86_64&);
+ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_x86_64&, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024]);
+
+ // ppc specific variants
+ static int lastRestoreReg(const Registers_ppc&);
+ static bool isReturnAddressRegister(int regNum, const Registers_ppc&);
+ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_ppc&);
+ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_ppc&);
+ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_ppc&, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024]);
+};
+
+
+
+
+template <typename A, typename R>
+const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
+ CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn)
+{
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ CFI_Atom_Info<A>* entry = infos;
+ CFI_Atom_Info<A>* end = &infos[infosCount];
+ const pint_t ehSectionEnd = ehSectionStart + sectionLength;
+ for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
+ pint_t currentCFI = p;
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return NULL; // end marker
+ if ( entry >= end )
+ return "too little space allocated for parseCFIs";
+ pint_t nextCFI = p + cfiLength;
+ uint32_t id = addressSpace.get32(p);
+ if ( id == 0 ) {
+ // is CIE
+ const char* err = CFI_Parser<A>::parseCIE(addressSpace, currentCFI, &cieInfo);
+ if ( err != NULL )
+ return err;
+ entry->address = currentCFI;
+ entry->size = nextCFI - currentCFI;
+ entry->isCIE = true;
+ entry->u.cieInfo.personality.targetAddress = cieInfo.personality;
+ entry->u.cieInfo.personality.offsetInCFI = cieInfo.personalityOffsetInCIE;
+ entry->u.cieInfo.personality.encodingOfTargetAddress = cieInfo.personalityEncoding;
+ ++entry;
+ }
+ else {
+ // is FDE
+ entry->address = currentCFI;
+ entry->size = nextCFI - currentCFI;
+ entry->isCIE = false;
+ entry->u.fdeInfo.function.targetAddress = CFI_INVALID_ADDRESS;
+ entry->u.fdeInfo.cie.targetAddress = CFI_INVALID_ADDRESS;
+ entry->u.fdeInfo.lsda.targetAddress = CFI_INVALID_ADDRESS;
+ uint32_t ciePointer = addressSpace.get32(p);
+ pint_t cieStart = p-ciePointer;
+ // validate pointer to CIE is within section
+ if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
+ return "FDE points to CIE outside __eh_frame section";
+ // optimize usual case where cie is same for all FDEs
+ if ( cieStart != cieInfo.cieStart ) {
+ const char* err = CFI_Parser<A>::parseCIE(addressSpace, cieStart, &cieInfo);
+ if ( err != NULL )
+ return err;
+ }
+ entry->u.fdeInfo.cie.targetAddress = cieStart;
+ entry->u.fdeInfo.cie.offsetInCFI = p-currentCFI;
+ entry->u.fdeInfo.cie.encodingOfTargetAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
+ p += 4;
+ // parse pc begin and range
+ pint_t offsetOfFunctionAddress = p-currentCFI;
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
+ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ // test if pc is within the function this FDE covers
+ entry->u.fdeInfo.function.targetAddress = pcStart;
+ entry->u.fdeInfo.function.offsetInCFI = offsetOfFunctionAddress;
+ entry->u.fdeInfo.function.encodingOfTargetAddress = cieInfo.pointerEncoding;
+ // check for augmentation length
+ if ( cieInfo.fdesHaveAugmentationData ) {
+ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if ( cieInfo.lsdaEncoding != 0 ) {
+ // peek at value (without indirection). Zero means no lsda
+ pint_t lsdaStart = p;
+ if ( addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding & 0x0F) != 0 ) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ pint_t offsetOfLSDAAddress = p-currentCFI;
+ entry->u.fdeInfo.lsda.targetAddress = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
+ entry->u.fdeInfo.lsda.offsetInCFI = offsetOfLSDAAddress;
+ entry->u.fdeInfo.lsda.encodingOfTargetAddress = cieInfo.lsdaEncoding;
+ }
+ }
+ p = endOfAug;
+ }
+ // compute compact unwind encoding
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ fdeInfo.fdeStart = currentCFI;
+ fdeInfo.fdeLength = nextCFI - currentCFI;
+ fdeInfo.fdeInstructions = p;
+ fdeInfo.pcStart = pcStart;
+ fdeInfo.pcEnd = pcStart + pcRange;
+ fdeInfo.lsda = entry->u.fdeInfo.lsda.targetAddress;
+ typename CFI_Parser<A>::PrologInfo prolog;
+ R dummy; // for proper selection of architecture specific functions
+ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
+ char warningBuffer[1024];
+ entry->u.fdeInfo.compactUnwindInfo = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
+ if ( fdeInfo.lsda != CFI_INVALID_ADDRESS )
+ entry->u.fdeInfo.compactUnwindInfo |= UNWIND_HAS_LSDA;
+ if ( warningBuffer[0] != '\0' )
+ warn(ref, fdeInfo.pcStart, warningBuffer);
+ }
+ else {
+ warn(ref, CFI_INVALID_ADDRESS, "dwarf unwind instructions could not be parsed");
+ entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy);
+ }
+ ++entry;
+ }
+ p = nextCFI;
+ }
+ if ( entry != end )
+ return "wrong entry count for parseCFIs";
+ return NULL; // success
+}
+
+
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart,
+ pint_t* lsda, pint_t* personality,
+ char warningBuffer[1024])
+{
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ R dummy; // for proper selection of architecture specific functions
+ if ( CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
+ *lsda = fdeInfo.lsda;
+ *personality = cieInfo.personality;
+ compact_unwind_encoding_t encoding;
+ encoding = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
+ if ( fdeInfo.lsda != 0 )
+ encoding |= UNWIND_HAS_LSDA;
+ return encoding;
+ }
+ else {
+ strcpy(warningBuffer, "dwarf unwind instructions could not be parsed");
+ return encodeToUseDwarf(dummy);
+ }
+ }
+ else {
+ strcpy(warningBuffer, "dwarf FDE could not be parsed");
+ return encodeToUseDwarf(dummy);
+ }
+}
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getSavedRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg)
+{
+ switch ( savedReg.location ) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getP(cfa + savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getP(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ return evaluateExpression(savedReg.value, addressSpace, registers, cfa);
+
+ case CFI_Parser<A>::kRegisterInRegister:
+ return registers.getRegister(savedReg.value);
+
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ // FIX ME
+ break;
+ }
+ ABORT("unsupported restore location for register");
+}
+
+template <typename A, typename R>
+double DwarfInstructions<A,R>::getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg)
+{
+ switch ( savedReg.location ) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getDouble(cfa + savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getDouble(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ case CFI_Parser<A>::kRegisterInRegister:
+ // FIX ME
+ break;
+ }
+ ABORT("unsupported restore location for float register");
+}
+
+template <typename A, typename R>
+v128 DwarfInstructions<A,R>::getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa,
+ const typename CFI_Parser<A>::RegisterLocation& savedReg)
+{
+ switch ( savedReg.location ) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getVector(cfa + savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getVector(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ case CFI_Parser<A>::kRegisterInRegister:
+ // FIX ME
+ break;
+ }
+ ABORT("unsupported restore location for vector register");
+}
+
+
+template <typename A, typename R>
+int DwarfInstructions<A,R>::stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers)
+{
+ //fprintf(stderr, "stepWithDwarf(pc=0x%0llX, fdeStart=0x%0llX)\n", (uint64_t)pc, (uint64_t)fdeStart);
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ if ( CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
+ R newRegisters = registers;
+
+ // get pointer to cfa (architecture specific)
+ pint_t cfa = getCFA(addressSpace, prolog, registers);
+
+ // restore registers that dwarf says were saved
+ pint_t returnAddress = 0;
+ for (int i=0; i <= lastRestoreReg(newRegisters); ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+ if ( registers.validFloatRegister(i) )
+ newRegisters.setFloatRegister(i, getSavedFloatRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
+ else if ( registers.validVectorRegister(i) )
+ newRegisters.setVectorRegister(i, getSavedVectorRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
+ else if ( isReturnAddressRegister(i, registers) )
+ returnAddress = getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]);
+ else if ( registers.validRegister(i) )
+ newRegisters.setRegister(i, getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
+ else
+ return UNW_EBADREG;
+ }
+ }
+
+ // by definition the CFA is the stack pointer at the call site, so restoring SP means setting it to CFA
+ newRegisters.setSP(cfa);
+
+ // return address is address after call site instruction, so setting IP to that does a return
+ newRegisters.setIP(returnAddress);
+
+ // do the actual step by replacing the register set with the new ones
+ registers = newRegisters;
+
+ return UNW_STEP_SUCCESS;
+ }
+ }
+ return UNW_EBADFRAME;
+}
+
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::evaluateExpression(pint_t expression, A& addressSpace,
+ const R& registers, pint_t initialStackValue)
+{
+ const bool log = false;
+ pint_t p = expression;
+ pint_t expressionEnd = expression+20; // just need something until length is read
+ uint64_t length = addressSpace.getULEB128(p, expressionEnd);
+ expressionEnd = p + length;
+ if (log) fprintf(stderr, "evaluateExpression(): length=%llu\n", length);
+ pint_t stack[100];
+ pint_t* sp = stack;
+ *(++sp) = initialStackValue;
+
+ while ( p < expressionEnd ) {
+ if (log) {
+ for(pint_t* t = sp; t > stack; --t) {
+ fprintf(stderr, "sp[] = 0x%llX\n", (uint64_t)(*t));
+ }
+ }
+ uint8_t opcode = addressSpace.get8(p++);
+ sint_t svalue;
+ pint_t value;
+ uint32_t reg;
+ switch (opcode) {
+ case DW_OP_addr:
+ // push immediate address sized value
+ value = addressSpace.getP(p);
+ p += sizeof(pint_t);
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_deref:
+ // pop stack, dereference, push result
+ value = *sp--;
+ *(++sp) = addressSpace.getP(value);
+ if (log) fprintf(stderr, "dereference 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const1u:
+ // push immediate 1 byte value
+ value = addressSpace.get8(p);
+ p += 1;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const1s:
+ // push immediate 1 byte signed value
+ svalue = (int8_t)addressSpace.get8(p);
+ p += 1;
+ *(++sp) = svalue;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_const2u:
+ // push immediate 2 byte value
+ value = addressSpace.get16(p);
+ p += 2;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const2s:
+ // push immediate 2 byte signed value
+ svalue = (int16_t)addressSpace.get16(p);
+ p += 2;
+ *(++sp) = svalue;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_const4u:
+ // push immediate 4 byte value
+ value = addressSpace.get32(p);
+ p += 4;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const4s:
+ // push immediate 4 byte signed value
+ svalue = (int32_t)addressSpace.get32(p);
+ p += 4;
+ *(++sp) = svalue;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_const8u:
+ // push immediate 8 byte value
+ value = addressSpace.get64(p);
+ p += 8;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const8s:
+ // push immediate 8 byte signed value
+ value = (int32_t)addressSpace.get64(p);
+ p += 8;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_constu:
+ // push immediate ULEB128 value
+ value = addressSpace.getULEB128(p, expressionEnd);
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_consts:
+ // push immediate SLEB128 value
+ svalue = addressSpace.getSLEB128(p, expressionEnd);
+ *(++sp) = svalue;
+ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_dup:
+ // push top of stack
+ value = *sp;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "duplicate top of stack\n");
+ break;
+
+ case DW_OP_drop:
+ // pop
+ --sp;
+ if (log) fprintf(stderr, "pop top of stack\n");
+ break;
+
+ case DW_OP_over:
+ // dup second
+ value = sp[-1];
+ *(++sp) = value;
+ if (log) fprintf(stderr, "duplicate second in stack\n");
+ break;
+
+ case DW_OP_pick:
+ // pick from
+ reg = addressSpace.get8(p);
+ p += 1;
+ value = sp[-reg];
+ *(++sp) = value;
+ if (log) fprintf(stderr, "duplicate %d in stack\n", reg);
+ break;
+
+ case DW_OP_swap:
+ // swap top two
+ value = sp[0];
+ sp[0] = sp[-1];
+ sp[-1] = value;
+ if (log) fprintf(stderr, "swap top of stack\n");
+ break;
+
+ case DW_OP_rot:
+ // rotate top three
+ value = sp[0];
+ sp[0] = sp[-1];
+ sp[-1] = sp[-2];
+ sp[-2] = value;
+ if (log) fprintf(stderr, "rotate top three of stack\n");
+ break;
+
+ case DW_OP_xderef:
+ // pop stack, dereference, push result
+ value = *sp--;
+ *sp = *((uint64_t*)value);
+ if (log) fprintf(stderr, "x-dereference 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_abs:
+ svalue = *sp;
+ if ( svalue < 0 )
+ *sp = -svalue;
+ if (log) fprintf(stderr, "abs\n");
+ break;
+
+ case DW_OP_and:
+ value = *sp--;
+ *sp &= value;
+ if (log) fprintf(stderr, "and\n");
+ break;
+
+ case DW_OP_div:
+ svalue = *sp--;
+ *sp = *sp / svalue;
+ if (log) fprintf(stderr, "div\n");
+ break;
+
+ case DW_OP_minus:
+ svalue = *sp--;
+ *sp = *sp - svalue;
+ if (log) fprintf(stderr, "minus\n");
+ break;
+
+ case DW_OP_mod:
+ svalue = *sp--;
+ *sp = *sp % svalue;
+ if (log) fprintf(stderr, "module\n");
+ break;
+
+ case DW_OP_mul:
+ svalue = *sp--;
+ *sp = *sp * svalue;
+ if (log) fprintf(stderr, "mul\n");
+ break;
+
+ case DW_OP_neg:
+ *sp = 0 - *sp;
+ if (log) fprintf(stderr, "neg\n");
+ break;
+
+ case DW_OP_not:
+ svalue = *sp;
+ *sp = ~svalue;
+ if (log) fprintf(stderr, "not\n");
+ break;
+
+ case DW_OP_or:
+ value = *sp--;
+ *sp |= value;
+ if (log) fprintf(stderr, "or\n");
+ break;
+
+ case DW_OP_plus:
+ value = *sp--;
+ *sp += value;
+ if (log) fprintf(stderr, "plus\n");
+ break;
+
+ case DW_OP_plus_uconst:
+ // pop stack, add uelb128 constant, push result
+ *sp += addressSpace.getULEB128(p, expressionEnd);
+ if (log) fprintf(stderr, "add constant\n");
+ break;
+
+ case DW_OP_shl:
+ value = *sp--;
+ *sp = *sp << value;
+ if (log) fprintf(stderr, "shift left\n");
+ break;
+
+ case DW_OP_shr:
+ value = *sp--;
+ *sp = *sp >> value;
+ if (log) fprintf(stderr, "shift left\n");
+ break;
+
+ case DW_OP_shra:
+ value = *sp--;
+ svalue = *sp;
+ *sp = svalue >> value;
+ if (log) fprintf(stderr, "shift left arithmetric\n");
+ break;
+
+ case DW_OP_xor:
+ value = *sp--;
+ *sp ^= value;
+ if (log) fprintf(stderr, "xor\n");
+ break;
+
+ case DW_OP_skip:
+ svalue = (int16_t)addressSpace.get16(p);
+ p += 2;
+ p += svalue;
+ if (log) fprintf(stderr, "skip %lld\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_bra:
+ svalue = (int16_t)addressSpace.get16(p);
+ p += 2;
+ if ( *sp-- )
+ p += svalue;
+ if (log) fprintf(stderr, "bra %lld\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_eq:
+ value = *sp--;
+ *sp = (*sp == value);
+ if (log) fprintf(stderr, "eq\n");
+ break;
+
+ case DW_OP_ge:
+ value = *sp--;
+ *sp = (*sp >= value);
+ if (log) fprintf(stderr, "ge\n");
+ break;
+
+ case DW_OP_gt:
+ value = *sp--;
+ *sp = (*sp > value);
+ if (log) fprintf(stderr, "gt\n");
+ break;
+
+ case DW_OP_le:
+ value = *sp--;
+ *sp = (*sp <= value);
+ if (log) fprintf(stderr, "le\n");
+ break;
+
+ case DW_OP_lt:
+ value = *sp--;
+ *sp = (*sp < value);
+ if (log) fprintf(stderr, "lt\n");
+ break;
+
+ case DW_OP_ne:
+ value = *sp--;
+ *sp = (*sp != value);
+ if (log) fprintf(stderr, "ne\n");
+ break;
+
+ 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:
+ value = opcode - DW_OP_lit0;
+ *(++sp) = value;
+ if (log) fprintf(stderr, "push literal 0x%llX\n", (uint64_t)value);
+ break;
+
+ 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 = opcode - DW_OP_reg0;
+ *(++sp) = registers.getRegister(reg);
+ if (log) fprintf(stderr, "push reg %d\n", reg);
+ break;
+
+ case DW_OP_regx:
+ reg = addressSpace.getULEB128(p, expressionEnd);
+ *(++sp) = registers.getRegister(reg);
+ if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
+ 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:
+ reg = opcode - DW_OP_breg0;
+ svalue = addressSpace.getSLEB128(p, expressionEnd);
+ *(++sp) = registers.getRegister(reg) + svalue;
+ if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
+ break;
+
+ case DW_OP_bregx:
+ reg = addressSpace.getULEB128(p, expressionEnd);
+ svalue = addressSpace.getSLEB128(p, expressionEnd);
+ *(++sp) = registers.getRegister(reg) + svalue;
+ if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
+ break;
+
+ case DW_OP_fbreg:
+ ABORT("DW_OP_fbreg not implemented");
+ break;
+
+ case DW_OP_piece:
+ ABORT("DW_OP_piece not implemented");
+ break;
+
+ case DW_OP_deref_size:
+ // pop stack, dereference, push result
+ value = *sp--;
+ switch ( addressSpace.get8(p++) ) {
+ case 1:
+ value = addressSpace.get8(value);
+ break;
+ case 2:
+ value = addressSpace.get16(value);
+ break;
+ case 4:
+ value = addressSpace.get32(value);
+ break;
+ case 8:
+ value = addressSpace.get64(value);
+ break;
+ default:
+ ABORT("DW_OP_deref_size with bad size");
+ }
+ *(++sp) = value;
+ if (log) fprintf(stderr, "sized dereference 0x%llX\n", (uint64_t)value);
+ break;
+
+ case DW_OP_xderef_size:
+ case DW_OP_nop:
+ case DW_OP_push_object_addres:
+ case DW_OP_call2:
+ case DW_OP_call4:
+ case DW_OP_call_ref:
+ default:
+ ABORT("dwarf opcode not implemented");
+ }
+
+ }
+ if (log) fprintf(stderr, "expression evaluates to 0x%llX\n", (uint64_t)*sp);
+ return *sp;
+}
+
+
+
+//
+// x86_64 specific functions
+//
+
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_x86_64&)
+{
+ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)DW_X86_64_RET_ADDR );
+ return DW_X86_64_RET_ADDR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_x86_64&)
+{
+ return (regNum == DW_X86_64_RET_ADDR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
+ const Registers_x86_64& registers)
+{
+ if ( prolog.cfaRegister != 0 )
+ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+ else if ( prolog.cfaExpression != 0 )
+ return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
+ else
+ ABORT("getCFA(): unknown location for x86_64 cfa");
+}
+
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_x86_64&)
+{
+ return UNWIND_X86_64_MODE_DWARF;
+}
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_x86&)
+{
+ return UNWIND_X86_MODE_DWARF;
+}
+
+
+
+template <typename A, typename R>
+uint32_t DwarfInstructions<A,R>::getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure)
+{
+ if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 32) ) {
+ failure = true;
+ return 0;
+ }
+ unsigned int slotIndex = regOffsetFromBaseOffset/8;
+
+ switch ( reg ) {
+ case UNW_X86_64_RBX:
+ return UNWIND_X86_64_REG_RBX << (slotIndex*3);
+ case UNW_X86_64_R12:
+ return UNWIND_X86_64_REG_R12 << (slotIndex*3);
+ case UNW_X86_64_R13:
+ return UNWIND_X86_64_REG_R13 << (slotIndex*3);
+ case UNW_X86_64_R14:
+ return UNWIND_X86_64_REG_R14 << (slotIndex*3);
+ case UNW_X86_64_R15:
+ return UNWIND_X86_64_REG_R15 << (slotIndex*3);
+ }
+
+ // invalid register
+ failure = true;
+ return 0;
+}
+
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_x86_64& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024])
+{
+ warningBuffer[0] = '\0';
+
+ // don't create compact unwind info for unsupported dwarf kinds
+ if ( prolog.registerSavedMoreThanOnce ) {
+ strcpy(warningBuffer, "register saved more than once (might be shrink wrap)");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ if ( prolog.cfaOffsetWasNegative ) {
+ strcpy(warningBuffer, "cfa had negative offset (dwarf might contain epilog)");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ if ( prolog.spExtraArgSize != 0 ) {
+ strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+
+ // figure out which kind of frame this function uses
+ bool standardRBPframe = (
+ (prolog.cfaRegister == UNW_X86_64_RBP)
+ && (prolog.cfaRegisterOffset == 16)
+ && (prolog.savedRegisters[UNW_X86_64_RBP].location == CFI_Parser<A>::kRegisterInCFA)
+ && (prolog.savedRegisters[UNW_X86_64_RBP].value == -16) );
+ bool standardRSPframe = (prolog.cfaRegister == UNW_X86_64_RSP);
+ if ( !standardRBPframe && !standardRSPframe ) {
+ // no compact encoding for this
+ strcpy(warningBuffer, "does not use RBP or RSP based frame");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+
+ // scan which registers are saved
+ int saveRegisterCount = 0;
+ bool rbxSaved = false;
+ bool r12Saved = false;
+ bool r13Saved = false;
+ bool r14Saved = false;
+ bool r15Saved = false;
+ bool rbpSaved = false;
+ for (int i=0; i < 64; ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
+ sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ switch (i) {
+ case UNW_X86_64_RBX:
+ rbxSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_R12:
+ r12Saved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_R13:
+ r13Saved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_R14:
+ r14Saved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_R15:
+ r15Saved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_64_RBP:
+ rbpSaved = true;
+ ++saveRegisterCount;
+ break;
+ case DW_X86_64_RET_ADDR:
+ break;
+ default:
+ sprintf(warningBuffer, "non-standard register %d being saved in prolog", i);
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ }
+ }
+ const int64_t cfaOffsetRBX = prolog.savedRegisters[UNW_X86_64_RBX].value;
+ const int64_t cfaOffsetR12 = prolog.savedRegisters[UNW_X86_64_R12].value;
+ const int64_t cfaOffsetR13 = prolog.savedRegisters[UNW_X86_64_R13].value;
+ const int64_t cfaOffsetR14 = prolog.savedRegisters[UNW_X86_64_R14].value;
+ const int64_t cfaOffsetR15 = prolog.savedRegisters[UNW_X86_64_R15].value;
+ const int64_t cfaOffsetRBP = prolog.savedRegisters[UNW_X86_64_RBP].value;
+
+ // encode standard RBP frames
+ compact_unwind_encoding_t encoding = 0;
+ if ( standardRBPframe ) {
+ // | |
+ // +--------------+ <- CFA
+ // | ret addr |
+ // +--------------+
+ // | rbp |
+ // +--------------+ <- rbp
+ // ~ ~
+ // +--------------+
+ // | saved reg3 |
+ // +--------------+ <- CFA - offset+16
+ // | saved reg2 |
+ // +--------------+ <- CFA - offset+8
+ // | saved reg1 |
+ // +--------------+ <- CFA - offset
+ // | |
+ // +--------------+
+ // | |
+ // <- rsp
+ //
+ encoding = UNWIND_X86_64_MODE_RBP_FRAME;
+
+ // find save location of farthest register from rbp
+ int furthestCfaOffset = 0;
+ if ( rbxSaved & (cfaOffsetRBX < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetRBX;
+ if ( r12Saved & (cfaOffsetR12 < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetR12;
+ if ( r13Saved & (cfaOffsetR13 < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetR13;
+ if ( r14Saved & (cfaOffsetR14 < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetR14;
+ if ( r15Saved & (cfaOffsetR15 < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetR15;
+
+ if ( furthestCfaOffset == 0 ) {
+ // no registers saved, nothing more to encode
+ return encoding;
+ }
+
+ // add stack offset to encoding
+ int rbpOffset = furthestCfaOffset + 16;
+ int encodedOffset = rbpOffset/(-8);
+ if ( encodedOffset > 255 ) {
+ strcpy(warningBuffer, "offset of saved registers too far to encode");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_64_RBP_FRAME_OFFSET));
+
+ // add register saved from each stack location
+ bool encodingFailure = false;
+ if ( rbxSaved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_RBX, cfaOffsetRBX - furthestCfaOffset, encodingFailure);
+ if ( r12Saved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_R12, cfaOffsetR12 - furthestCfaOffset, encodingFailure);
+ if ( r13Saved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_R13, cfaOffsetR13 - furthestCfaOffset, encodingFailure);
+ if ( r14Saved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_R14, cfaOffsetR14 - furthestCfaOffset, encodingFailure);
+ if ( r15Saved )
+ encoding |= getRBPEncodedRegister(UNW_X86_64_R15, cfaOffsetR15 - furthestCfaOffset, encodingFailure);
+
+ if ( encodingFailure ){
+ strcpy(warningBuffer, "saved registers not contiguous");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+
+ return encoding;
+ }
+ else {
+ // | |
+ // +--------------+ <- CFA
+ // | ret addr |
+ // +--------------+
+ // | saved reg1 |
+ // +--------------+ <- CFA - 16
+ // | saved reg2 |
+ // +--------------+ <- CFA - 24
+ // | saved reg3 |
+ // +--------------+ <- CFA - 32
+ // | saved reg4 |
+ // +--------------+ <- CFA - 40
+ // | saved reg5 |
+ // +--------------+ <- CFA - 48
+ // | saved reg6 |
+ // +--------------+ <- CFA - 56
+ // | |
+ // <- esp
+ //
+
+ // for RSP based frames we need to encode stack size in unwind info
+ encoding = UNWIND_X86_64_MODE_STACK_IMMD;
+ uint64_t stackValue = prolog.cfaRegisterOffset / 8;
+ uint32_t stackAdjust = 0;
+ bool immedStackSize = true;
+ const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+ if ( stackValue > stackMaxImmedValue ) {
+ // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
+ pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
+ uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
+ stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/8;
+ stackValue = functionContentAdjustStackIns - funcAddr;
+ immedStackSize = false;
+ if ( stackAdjust > 7 ) {
+ strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ encoding = UNWIND_X86_64_MODE_STACK_IND;
+ }
+
+
+ // validate that saved registers are all within 6 slots abutting return address
+ int registers[6];
+ for (int i=0; i < 6;++i)
+ registers[i] = 0;
+ if ( r15Saved ) {
+ if ( cfaOffsetR15 < -56 ) {
+ strcpy(warningBuffer, "r15 is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetR15+56)/8] = UNWIND_X86_64_REG_R15;
+ }
+ if ( r14Saved ) {
+ if ( cfaOffsetR14 < -56 ) {
+ strcpy(warningBuffer, "r14 is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetR14+56)/8] = UNWIND_X86_64_REG_R14;
+ }
+ if ( r13Saved ) {
+ if ( cfaOffsetR13 < -56 ) {
+ strcpy(warningBuffer, "r13 is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetR13+56)/8] = UNWIND_X86_64_REG_R13;
+ }
+ if ( r12Saved ) {
+ if ( cfaOffsetR12 < -56 ) {
+ strcpy(warningBuffer, "r12 is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetR12+56)/8] = UNWIND_X86_64_REG_R12;
+ }
+ if ( rbxSaved ) {
+ if ( cfaOffsetRBX < -56 ) {
+ strcpy(warningBuffer, "rbx is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetRBX+56)/8] = UNWIND_X86_64_REG_RBX;
+ }
+ if ( rbpSaved ) {
+ if ( cfaOffsetRBP < -56 ) {
+ strcpy(warningBuffer, "rbp is saved too far from return address");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ registers[(cfaOffsetRBP+56)/8] = UNWIND_X86_64_REG_RBP;
+ }
+
+ // validate that saved registers are contiguous and abut return address on stack
+ for (int i=0; i < saveRegisterCount; ++i) {
+ if ( registers[5-i] == 0 ) {
+ strcpy(warningBuffer, "registers not save contiguously in stack");
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+ }
+
+ // encode register permutation
+ // the 10-bits are encoded differently depending on the number of registers saved
+ int renumregs[6];
+ for (int i=6-saveRegisterCount; i < 6; ++i) {
+ int countless = 0;
+ for (int j=6-saveRegisterCount; j < i; ++j) {
+ if ( registers[j] < registers[i] )
+ ++countless;
+ }
+ renumregs[i] = registers[i] - countless -1;
+ }
+ uint32_t permutationEncoding = 0;
+ switch ( saveRegisterCount ) {
+ case 6:
+ permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]);
+ break;
+ case 5:
+ permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]);
+ break;
+ case 4:
+ permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]);
+ break;
+ case 3:
+ permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]);
+ break;
+ case 2:
+ permutationEncoding |= (5*renumregs[4] + renumregs[5]);
+ break;
+ case 1:
+ permutationEncoding |= (renumregs[5]);
+ break;
+ }
+
+ encoding |= (stackValue << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_SIZE));
+ encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_ADJUST));
+ encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT));
+ encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION));
+ return encoding;
+ }
+}
+
+
+
+
+//
+// x86 specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_x86&)
+{
+ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)DW_X86_RET_ADDR );
+ return DW_X86_RET_ADDR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_x86&)
+{
+ return (regNum == DW_X86_RET_ADDR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
+ const Registers_x86& registers)
+{
+ if ( prolog.cfaRegister != 0 )
+ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+ else if ( prolog.cfaExpression != 0 )
+ return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
+ else
+ ABORT("getCFA(): unknown location for x86 cfa");
+}
+
+
+
+
+
+template <typename A, typename R>
+uint32_t DwarfInstructions<A,R>::getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure)
+{
+ if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 16) ) {
+ failure = true;
+ return 0;
+ }
+ unsigned int slotIndex = regOffsetFromBaseOffset/4;
+
+ switch ( reg ) {
+ case UNW_X86_EBX:
+ return UNWIND_X86_REG_EBX << (slotIndex*3);
+ case UNW_X86_ECX:
+ return UNWIND_X86_REG_ECX << (slotIndex*3);
+ case UNW_X86_EDX:
+ return UNWIND_X86_REG_EDX << (slotIndex*3);
+ case UNW_X86_EDI:
+ return UNWIND_X86_REG_EDI << (slotIndex*3);
+ case UNW_X86_ESI:
+ return UNWIND_X86_REG_ESI << (slotIndex*3);
+ }
+
+ // invalid register
+ failure = true;
+ return 0;
+}
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_x86& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024])
+{
+ warningBuffer[0] = '\0';
+
+ // don't create compact unwind info for unsupported dwarf kinds
+ if ( prolog.registerSavedMoreThanOnce ) {
+ strcpy(warningBuffer, "register saved more than once (might be shrink wrap)");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ if ( prolog.spExtraArgSize != 0 ) {
+ strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size");
+ return UNWIND_X86_MODE_DWARF;
+ }
+
+ // figure out which kind of frame this function uses
+ bool standardEBPframe = (
+ (prolog.cfaRegister == UNW_X86_EBP)
+ && (prolog.cfaRegisterOffset == 8)
+ && (prolog.savedRegisters[UNW_X86_EBP].location == CFI_Parser<A>::kRegisterInCFA)
+ && (prolog.savedRegisters[UNW_X86_EBP].value == -8) );
+ bool standardESPframe = (prolog.cfaRegister == UNW_X86_ESP);
+ if ( !standardEBPframe && !standardESPframe ) {
+ // no compact encoding for this
+ strcpy(warningBuffer, "does not use EBP or ESP based frame");
+ return UNWIND_X86_MODE_DWARF;
+ }
+
+ // scan which registers are saved
+ int saveRegisterCount = 0;
+ bool ebxSaved = false;
+ bool ecxSaved = false;
+ bool edxSaved = false;
+ bool esiSaved = false;
+ bool ediSaved = false;
+ bool ebpSaved = false;
+ for (int i=0; i < 64; ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
+ sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
+ return UNWIND_X86_MODE_DWARF;
+ }
+ switch (i) {
+ case UNW_X86_EBX:
+ ebxSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_ECX:
+ ecxSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_EDX:
+ edxSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_ESI:
+ esiSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_EDI:
+ ediSaved = true;
+ ++saveRegisterCount;
+ break;
+ case UNW_X86_EBP:
+ ebpSaved = true;
+ ++saveRegisterCount;
+ break;
+ case DW_X86_RET_ADDR:
+ break;
+ default:
+ sprintf(warningBuffer, "non-standard register %d being saved in prolog", i);
+ return UNWIND_X86_MODE_DWARF;
+ }
+ }
+ }
+ const int32_t cfaOffsetEBX = prolog.savedRegisters[UNW_X86_EBX].value;
+ const int32_t cfaOffsetECX = prolog.savedRegisters[UNW_X86_ECX].value;
+ const int32_t cfaOffsetEDX = prolog.savedRegisters[UNW_X86_EDX].value;
+ const int32_t cfaOffsetEDI = prolog.savedRegisters[UNW_X86_EDI].value;
+ const int32_t cfaOffsetESI = prolog.savedRegisters[UNW_X86_ESI].value;
+ const int32_t cfaOffsetEBP = prolog.savedRegisters[UNW_X86_EBP].value;
+
+ // encode standard RBP frames
+ compact_unwind_encoding_t encoding = 0;
+ if ( standardEBPframe ) {
+ // | |
+ // +--------------+ <- CFA
+ // | ret addr |
+ // +--------------+
+ // | ebp |
+ // +--------------+ <- ebp
+ // ~ ~
+ // +--------------+
+ // | saved reg3 |
+ // +--------------+ <- CFA - offset+8
+ // | saved reg2 |
+ // +--------------+ <- CFA - offset+e
+ // | saved reg1 |
+ // +--------------+ <- CFA - offset
+ // | |
+ // +--------------+
+ // | |
+ // <- esp
+ //
+ encoding = UNWIND_X86_MODE_EBP_FRAME;
+
+ // find save location of farthest register from ebp
+ int furthestCfaOffset = 0;
+ if ( ebxSaved & (cfaOffsetEBX < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetEBX;
+ if ( ecxSaved & (cfaOffsetECX < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetECX;
+ if ( edxSaved & (cfaOffsetEDX < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetEDX;
+ if ( ediSaved & (cfaOffsetEDI < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetEDI;
+ if ( esiSaved & (cfaOffsetESI < furthestCfaOffset) )
+ furthestCfaOffset = cfaOffsetESI;
+
+ if ( furthestCfaOffset == 0 ) {
+ // no registers saved, nothing more to encode
+ return encoding;
+ }
+
+ // add stack offset to encoding
+ int ebpOffset = furthestCfaOffset + 8;
+ int encodedOffset = ebpOffset/(-4);
+ if ( encodedOffset > 255 ) {
+ strcpy(warningBuffer, "offset of saved registers too far to encode");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_EBP_FRAME_OFFSET));
+
+ // add register saved from each stack location
+ bool encodingFailure = false;
+ if ( ebxSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_EBX, cfaOffsetEBX - furthestCfaOffset, encodingFailure);
+ if ( ecxSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_ECX, cfaOffsetECX - furthestCfaOffset, encodingFailure);
+ if ( edxSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_EDX, cfaOffsetEDX - furthestCfaOffset, encodingFailure);
+ if ( ediSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_EDI, cfaOffsetEDI - furthestCfaOffset, encodingFailure);
+ if ( esiSaved )
+ encoding |= getEBPEncodedRegister(UNW_X86_ESI, cfaOffsetESI - furthestCfaOffset, encodingFailure);
+
+ if ( encodingFailure ){
+ strcpy(warningBuffer, "saved registers not contiguous");
+ return UNWIND_X86_MODE_DWARF;
+ }
+
+ return encoding;
+ }
+ else {
+ // | |
+ // +--------------+ <- CFA
+ // | ret addr |
+ // +--------------+
+ // | saved reg1 |
+ // +--------------+ <- CFA - 8
+ // | saved reg2 |
+ // +--------------+ <- CFA - 12
+ // | saved reg3 |
+ // +--------------+ <- CFA - 16
+ // | saved reg4 |
+ // +--------------+ <- CFA - 20
+ // | saved reg5 |
+ // +--------------+ <- CFA - 24
+ // | saved reg6 |
+ // +--------------+ <- CFA - 28
+ // | |
+ // <- esp
+ //
+
+ // for ESP based frames we need to encode stack size in unwind info
+ encoding = UNWIND_X86_MODE_STACK_IMMD;
+ uint64_t stackValue = prolog.cfaRegisterOffset / 4;
+ uint32_t stackAdjust = 0;
+ bool immedStackSize = true;
+ const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_FRAMELESS_STACK_SIZE);
+ if ( stackValue > stackMaxImmedValue ) {
+ // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
+ pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
+ uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
+ stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/4;
+ stackValue = functionContentAdjustStackIns - funcAddr;
+ immedStackSize = false;
+ if ( stackAdjust > 7 ) {
+ strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ encoding = UNWIND_X86_MODE_STACK_IND;
+ }
+
+
+ // validate that saved registers are all within 6 slots abutting return address
+ int registers[6];
+ for (int i=0; i < 6;++i)
+ registers[i] = 0;
+ if ( ebxSaved ) {
+ if ( cfaOffsetEBX < -28 ) {
+ strcpy(warningBuffer, "ebx is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetEBX+28)/4] = UNWIND_X86_REG_EBX;
+ }
+ if ( ecxSaved ) {
+ if ( cfaOffsetECX < -28 ) {
+ strcpy(warningBuffer, "ecx is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetECX+28)/4] = UNWIND_X86_REG_ECX;
+ }
+ if ( edxSaved ) {
+ if ( cfaOffsetEDX < -28 ) {
+ strcpy(warningBuffer, "edx is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetEDX+28)/4] = UNWIND_X86_REG_EDX;
+ }
+ if ( ediSaved ) {
+ if ( cfaOffsetEDI < -28 ) {
+ strcpy(warningBuffer, "edi is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetEDI+28)/4] = UNWIND_X86_REG_EDI;
+ }
+ if ( esiSaved ) {
+ if ( cfaOffsetESI < -28 ) {
+ strcpy(warningBuffer, "esi is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetESI+28)/4] = UNWIND_X86_REG_ESI;
+ }
+ if ( ebpSaved ) {
+ if ( cfaOffsetEBP < -28 ) {
+ strcpy(warningBuffer, "ebp is saved too far from return address");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ registers[(cfaOffsetEBP+28)/4] = UNWIND_X86_REG_EBP;
+ }
+
+ // validate that saved registers are contiguous and abut return address on stack
+ for (int i=0; i < saveRegisterCount; ++i) {
+ if ( registers[5-i] == 0 ) {
+ strcpy(warningBuffer, "registers not save contiguously in stack");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ }
+
+ // encode register permutation
+ // the 10-bits are encoded differently depending on the number of registers saved
+ int renumregs[6];
+ for (int i=6-saveRegisterCount; i < 6; ++i) {
+ int countless = 0;
+ for (int j=6-saveRegisterCount; j < i; ++j) {
+ if ( registers[j] < registers[i] )
+ ++countless;
+ }
+ renumregs[i] = registers[i] - countless -1;
+ }
+ uint32_t permutationEncoding = 0;
+ switch ( saveRegisterCount ) {
+ case 6:
+ permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]);
+ break;
+ case 5:
+ permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]);
+ break;
+ case 4:
+ permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]);
+ break;
+ case 3:
+ permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]);
+ break;
+ case 2:
+ permutationEncoding |= (5*renumregs[4] + renumregs[5]);
+ break;
+ case 1:
+ permutationEncoding |= (renumregs[5]);
+ break;
+ }
+
+ encoding |= (stackValue << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_SIZE));
+ encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_ADJUST));
+ encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_COUNT));
+ encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION));
+ return encoding;
+ }
+}
+
+
+
+
+
+
+
+//
+// ppc specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_ppc&)
+{
+ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)UNW_PPC_SPEFSCR );
+ return UNW_PPC_SPEFSCR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_ppc&)
+{
+ return (regNum == UNW_PPC_LR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
+ const Registers_ppc& registers)
+{
+ if ( prolog.cfaRegister != 0 )
+ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+ else if ( prolog.cfaExpression != 0 )
+ return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
+ else
+ ABORT("getCFA(): unknown location for ppc cfa");
+}
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_ppc&)
+{
+ return UNWIND_X86_MODE_DWARF;
+}
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_ppc& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024])
+{
+ warningBuffer[0] = '\0';
+ return UNWIND_X86_MODE_DWARF;
+}
+
+
+
+
+} // namespace lldb_private
+
+
+#endif // __DWARF_INSTRUCTIONS_HPP__
+
+
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/DwarfParser.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/DwarfParser.hpp
new file mode 100644
index 00000000000..b11cb8ce441
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/DwarfParser.hpp
@@ -0,0 +1,869 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- DwarfParser.hpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//
+// processor specific parsing of dwarf unwind instructions
+//
+
+#ifndef __DWARF_PARSER_HPP__
+#define __DWARF_PARSER_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <vector>
+
+#include "libunwind.h"
+#include "dwarf2.h"
+
+#include "AddressSpace.hpp"
+#include "RemoteUnwindProfile.h"
+
+namespace lldb_private {
+
+
+///
+/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
+/// See Dwarf Spec for details:
+/// http://www.linux-foundation.org/spec/booksets/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+///
+template <typename A>
+class CFI_Parser
+{
+public:
+ typedef typename A::pint_t pint_t;
+
+ ///
+ /// Information encoded in a CIE (Common Information Entry)
+ ///
+ struct CIE_Info {
+ pint_t cieStart;
+ pint_t cieLength;
+ pint_t cieInstructions;
+ uint8_t pointerEncoding;
+ uint8_t lsdaEncoding;
+ uint8_t personalityEncoding;
+ uint8_t personalityOffsetInCIE;
+ pint_t personality;
+ int codeAlignFactor;
+ int dataAlignFactor;
+ bool isSignalFrame;
+ bool fdesHaveAugmentationData;
+ };
+
+ ///
+ /// Information about an FDE (Frame Description Entry)
+ ///
+ struct FDE_Info {
+ pint_t fdeStart;
+ pint_t fdeLength;
+ pint_t fdeInstructions;
+ pint_t pcStart;
+ pint_t pcEnd;
+ pint_t lsda;
+ };
+
+ ///
+ /// Used by linker when parsing __eh_frame section
+ ///
+ struct FDE_Reference {
+ pint_t address;
+ uint32_t offsetInFDE;
+ uint8_t encodingOfAddress;
+ };
+ struct FDE_Atom_Info {
+ pint_t fdeAddress;
+ FDE_Reference function;
+ FDE_Reference cie;
+ FDE_Reference lsda;
+ };
+ struct CIE_Atom_Info {
+ pint_t cieAddress;
+ FDE_Reference personality;
+ };
+
+
+ ///
+ /// Information about a frame layout and registers saved determined
+ /// by "running" the dwarf FDE "instructions"
+ ///
+ enum { kMaxRegisterNumber = 120 };
+ enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, kRegisterOffsetFromCFA,
+ kRegisterInRegister, kRegisterAtExpression, kRegisterIsExpression } ;
+ struct RegisterLocation {
+ RegisterSavedWhere location;
+ int64_t value;
+ };
+ struct PrologInfo {
+ uint32_t cfaRegister;
+ int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
+ int64_t cfaExpression; // CFA = expression
+ bool registersInOtherRegisters;
+ bool registerSavedMoreThanOnce;
+ bool cfaOffsetWasNegative;
+ uint32_t spExtraArgSize;
+ uint32_t codeOffsetAtStackDecrement;
+
+ RegisterLocation savedRegisters[kMaxRegisterNumber]; // from where to restore registers
+ };
+
+ struct PrologInfoStackEntry {
+ PrologInfoStackEntry(PrologInfoStackEntry* n, const PrologInfo& i)
+ : next(n), info(i) {}
+ PrologInfoStackEntry* next;
+ PrologInfo info;
+ };
+
+ static bool findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo);
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+ static bool functionFuncBoundsViaFDE(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, std::vector<FuncBounds> &funcbounds);
+#endif
+
+ static const char* decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo);
+ static bool parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results);
+ static const char* getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
+ std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies);
+ static uint32_t getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength);
+
+ static const char* parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo);
+
+private:
+ static bool parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
+ pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results);
+
+};
+
+
+///
+/// Parse a FDE into a CIE_Info and an FDE_Info
+///
+template <typename A>
+const char* CFI_Parser<A>::decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo)
+{
+ pint_t p = fdeStart;
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return "FDE has zero length"; // end marker
+ uint32_t ciePointer = addressSpace.get32(p);
+ if ( ciePointer == 0 )
+ return "FDE is really a CIE"; // this is a CIE not an FDE
+ pint_t nextCFI = p + cfiLength;
+ pint_t cieStart = p-ciePointer;
+ const char* err = parseCIE(addressSpace, cieStart, cieInfo);
+ if (err != NULL)
+ return err;
+ p += 4;
+ // parse pc begin and range
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+ // parse rest of info
+ fdeInfo->lsda = 0;
+ // check for augmentation length
+ if ( cieInfo->fdesHaveAugmentationData ) {
+ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if ( cieInfo->lsdaEncoding != 0 ) {
+ // peek at value (without indirection). Zero means no lsda
+ pint_t lsdaStart = p;
+ if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+ }
+ }
+ p = endOfAug;
+ }
+ fdeInfo->fdeStart = fdeStart;
+ fdeInfo->fdeLength = nextCFI - fdeStart;
+ fdeInfo->fdeInstructions = p;
+ fdeInfo->pcStart = pcStart;
+ fdeInfo->pcEnd = pcStart+pcRange;
+ return NULL; // success
+}
+
+
+///
+/// Scan an eh_frame section to find an FDE for a pc
+///
+template <typename A>
+bool CFI_Parser<A>::findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo)
+{
+ //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
+ pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
+ const pint_t ehSectionEnd = p + sectionLength;
+ while ( p < ehSectionEnd ) {
+ pint_t currentCFI = p;
+ //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return false; // end marker
+ uint32_t id = addressSpace.get32(p);
+ if ( id == 0 ) {
+ // skip over CIEs
+ p += cfiLength;
+ }
+ else {
+ // process FDE to see if it covers pc
+ pint_t nextCFI = p + cfiLength;
+ uint32_t ciePointer = addressSpace.get32(p);
+ pint_t cieStart = p-ciePointer;
+ // validate pointer to CIE is within section
+ if ( (ehSectionStart <= cieStart) && (cieStart < ehSectionEnd) ) {
+ if ( parseCIE(addressSpace, cieStart, cieInfo) == NULL ) {
+ p += 4;
+ // parse pc begin and range
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ // test if pc is within the function this FDE covers
+ if ( (pcStart < pc) && (pc <= pcStart+pcRange) ) {
+ // parse rest of info
+ fdeInfo->lsda = 0;
+ // check for augmentation length
+ if ( cieInfo->fdesHaveAugmentationData ) {
+ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if ( cieInfo->lsdaEncoding != 0 ) {
+ // peek at value (without indirection). Zero means no lsda
+ pint_t lsdaStart = p;
+ if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+ }
+ }
+ p = endOfAug;
+ }
+ fdeInfo->fdeStart = currentCFI;
+ fdeInfo->fdeLength = nextCFI - currentCFI;
+ fdeInfo->fdeInstructions = p;
+ fdeInfo->pcStart = pcStart;
+ fdeInfo->pcEnd = pcStart+pcRange;
+ //fprintf(stderr, "findFDE(pc=0x%llX) found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ return true;
+ }
+ else {
+ //fprintf(stderr, "findFDE(pc=0x%llX) not found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ // pc is not in begin/range, skip this FDE
+ }
+ }
+ else {
+ // malformed CIE, now augmentation describing pc range encoding
+ //fprintf(stderr, "malformed CIE\n");
+ }
+ }
+ else {
+ // malformed FDE. CIE is bad
+ //fprintf(stderr, "malformed FDE, cieStart=0x%llX, ehSectionStart=0x%llX, ehSectionEnd=0x%llX\n",
+ // (uint64_t)cieStart, (uint64_t)ehSectionStart, (uint64_t)ehSectionEnd);
+ }
+ p = nextCFI;
+ }
+ }
+ //fprintf(stderr, "findFDE(pc=0x%llX) not found\n",(uint64_t)pc);
+ return false;
+}
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+/// Scan an eh_frame section to find all the function start addresses
+/// This is only made for working with libunwind-remote. It copies
+/// the eh_frame section into local memory and steps through it quickly
+/// to find the start addresses of the CFIs.
+///
+template <typename A>
+bool CFI_Parser<A>::functionFuncBoundsViaFDE(A& addressSpace, pint_t ehSectionStart,
+ uint32_t sectionLength, std::vector<FuncBounds> &funcbounds)
+{
+ //fprintf(stderr, "functionFuncBoundsViaFDE(0x%llX)\n", (long long)pc);
+ pint_t p = ehSectionStart;
+ const pint_t ehSectionEnd = p + sectionLength;
+ pint_t lastCieSeen = (pint_t) -1;
+ CIE_Info cieInfo;
+ while ( p < ehSectionEnd ) {
+ //fprintf(stderr, "functionFuncBoundsViaFDE() CFI at 0x%llX\n", (long long)p);
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return false; // end marker
+ uint32_t id = addressSpace.get32(p);
+ if ( id == 0 ) {
+ // skip over CIEs
+ p += cfiLength;
+ }
+ else {
+ // process FDE to see if it covers pc
+ pint_t nextCFI = p + cfiLength;
+ uint32_t ciePointer = addressSpace.get32(p);
+ pint_t cieStart = p-ciePointer;
+ // validate pointer to CIE is within section
+ if ( (ehSectionStart <= cieStart) && (cieStart < ehSectionEnd) ) {
+ const char *errmsg;
+ // don't re-parse the cie if this fde is pointing to one we already parsed
+ if (cieStart == lastCieSeen) {
+ errmsg = NULL;
+ }
+ else {
+ errmsg = parseCIE(addressSpace, cieStart, &cieInfo);
+ if (errmsg == NULL)
+ lastCieSeen = cieStart;
+ }
+ if ( errmsg == NULL ) {
+ p += 4;
+ // parse pc begin and range
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
+ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ funcbounds.push_back(FuncBounds(pcStart, pcStart + pcRange));
+ }
+ else {
+ // malformed CIE, now augmentation describing pc range encoding
+ //fprintf(stderr, "malformed CIE\n");
+ return false;
+ }
+ }
+ else {
+ // malformed FDE. CIE is bad
+ //fprintf(stderr, "malformed FDE, cieStart=0x%llX, ehSectionStart=0x%llX, ehSectionEnd=0x%llX\n",
+ // (uint64_t)cieStart, (uint64_t)ehSectionStart, (uint64_t)ehSectionEnd);
+ return false;
+ }
+ p = nextCFI;
+ }
+ }
+ return true;
+}
+#endif // SUPPORT_REMOTE_UNWINDING
+
+
+
+///
+/// Extract info from a CIE
+///
+template <typename A>
+const char* CFI_Parser<A>::parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo)
+{
+ //fprintf(stderr, "parseCIE(0x%llX)\n", (long long)cie);
+ cieInfo->pointerEncoding = 0;
+ cieInfo->lsdaEncoding = 0;
+ cieInfo->personalityEncoding = 0;
+ cieInfo->personalityOffsetInCIE = 0;
+ cieInfo->personality = 0;
+ cieInfo->codeAlignFactor = 0;
+ cieInfo->dataAlignFactor = 0;
+ cieInfo->isSignalFrame = false;
+ cieInfo->fdesHaveAugmentationData = false;
+ cieInfo->cieStart = cie;
+ pint_t p = cie;
+ uint64_t cieLength = addressSpace.get32(p);
+ p += 4;
+ pint_t cieContentEnd = p + cieLength;
+ if ( cieLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cieLength = addressSpace.get64(p);
+ p += 8;
+ cieContentEnd = p + cieLength;
+ }
+ if ( cieLength == 0 )
+ return false;
+ // CIE ID is always 0
+ if ( addressSpace.get32(p) != 0 )
+ return "CIE ID is not zero";
+ p += 4;
+ // Version is always 1 or 3
+ uint8_t version = addressSpace.get8(p);
+ if ( (version != 1) && (version != 3) )
+ return "CIE version is not 1 or 3";
+ ++p;
+ // save start of augmentation string and find end
+ pint_t strStart = p;
+ while ( addressSpace.get8(p) != 0 )
+ ++p;
+ ++p;
+ // parse code aligment factor
+ cieInfo->codeAlignFactor = addressSpace.getULEB128(p, cieContentEnd);
+ // parse data alignment factor
+ cieInfo->dataAlignFactor = addressSpace.getSLEB128(p, cieContentEnd);
+ // parse return address register
+ addressSpace.getULEB128(p, cieContentEnd);
+ // parse augmentation data based on augmentation string
+ const char* result = NULL;
+ if ( addressSpace.get8(strStart) == 'z' ) {
+ // parse augmentation data length
+ addressSpace.getULEB128(p, cieContentEnd);
+ for (pint_t s=strStart; addressSpace.get8(s) != '\0'; ++s) {
+ switch ( addressSpace.get8(s) ) {
+ case 'z':
+ cieInfo->fdesHaveAugmentationData = true;
+ break;
+ case 'P':
+ cieInfo->personalityEncoding = addressSpace.get8(p);
+ ++p;
+ cieInfo->personalityOffsetInCIE = p-cie;
+ cieInfo->personality = addressSpace.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
+ break;
+ case 'L':
+ cieInfo->lsdaEncoding = addressSpace.get8(p);
+ ++p;
+ break;
+ case 'R':
+ cieInfo->pointerEncoding = addressSpace.get8(p);
+ ++p;
+ break;
+ case 'S':
+ cieInfo->isSignalFrame = true;
+ break;
+ default:
+ // ignore unknown letters
+ break;
+ }
+ }
+ }
+ cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
+ cieInfo->cieInstructions = p;
+ return result;
+}
+
+
+template <typename A>
+uint32_t CFI_Parser<A>::getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength)
+{
+ uint32_t count = 0;
+ const pint_t ehSectionEnd = ehSectionStart + sectionLength;
+ for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return count; // end marker
+ ++count;
+ p += cfiLength;
+ }
+ return count;
+}
+
+
+
+template <typename A>
+const char* CFI_Parser<A>::getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
+ std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies)
+{
+ const pint_t ehSectionEnd = ehSectionStart + sectionLength;
+ for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
+ pint_t currentCFI = p;
+ uint64_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if ( cfiLength == 0xffffffff ) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = addressSpace.get64(p);
+ p += 8;
+ }
+ if ( cfiLength == 0 )
+ return NULL; // end marker
+ uint32_t id = addressSpace.get32(p);
+ if ( id == 0 ) {
+ // is CIE
+ CIE_Info cieInfo;
+ const char* err = parseCIE(addressSpace, currentCFI, &cieInfo);
+ if ( err != NULL )
+ return err;
+ CIE_Atom_Info entry;
+ entry.cieAddress = currentCFI;
+ entry.personality.address = cieInfo.personality;
+ entry.personality.offsetInFDE = cieInfo.personalityOffsetInCIE;
+ entry.personality.encodingOfAddress = cieInfo.personalityEncoding;
+ cies.push_back(entry);
+ p += cfiLength;
+ }
+ else {
+ // is FDE
+ FDE_Atom_Info entry;
+ entry.fdeAddress = currentCFI;
+ entry.function.address = 0;
+ entry.cie.address = 0;
+ entry.lsda.address = 0;
+ pint_t nextCFI = p + cfiLength;
+ uint32_t ciePointer = addressSpace.get32(p);
+ pint_t cieStart = p-ciePointer;
+ // validate pointer to CIE is within section
+ if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
+ return "FDE points to CIE outside __eh_frame section";
+ CIE_Info cieInfo;
+ const char* err = parseCIE(addressSpace, cieStart, &cieInfo);
+ if ( err != NULL )
+ return err;
+ entry.cie.address = cieStart;
+ entry.cie.offsetInFDE = p-currentCFI;
+ entry.cie.encodingOfAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
+ p += 4;
+ // parse pc begin and range
+ pint_t offsetOfFunctionAddress = p-currentCFI;
+ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
+ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
+ // test if pc is within the function this FDE covers
+ entry.function.address = pcStart;
+ entry.function.offsetInFDE = offsetOfFunctionAddress;
+ entry.function.encodingOfAddress = cieInfo.pointerEncoding;
+ // skip over augmentation length
+ if ( cieInfo.fdesHaveAugmentationData ) {
+ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if ( (cieInfo.lsdaEncoding != 0) && (addressSpace.getP(p) != 0) ) {
+ pint_t offsetOfLSDAAddress = p-currentCFI;
+ entry.lsda.address = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
+ entry.lsda.offsetInFDE = offsetOfLSDAAddress;
+ entry.lsda.encodingOfAddress = cieInfo.lsdaEncoding;
+ }
+ p = endOfAug;
+ }
+ fdes.push_back(entry);
+ p = nextCFI;
+ }
+ }
+ return NULL; // success
+}
+
+
+
+///
+/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE
+///
+template <typename A>
+bool CFI_Parser<A>::parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results)
+{
+ // clear results
+ bzero(results, sizeof(PrologInfo));
+ PrologInfoStackEntry* rememberStack = NULL;
+
+ // parse CIE then FDE instructions
+ return parseInstructions(addressSpace, cieInfo.cieInstructions, cieInfo.cieStart+cieInfo.cieLength,
+ cieInfo, (pint_t)(-1), rememberStack, results)
+ && parseInstructions(addressSpace, fdeInfo.fdeInstructions, fdeInfo.fdeStart+fdeInfo.fdeLength,
+ cieInfo, upToPC-fdeInfo.pcStart, rememberStack, results);
+}
+
+
+///
+/// "run" the dwarf instructions
+///
+template <typename A>
+bool CFI_Parser<A>::parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
+ pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results)
+{
+ const bool logDwarf = false;
+ pint_t p = instructions;
+ uint32_t codeOffset = 0;
+ PrologInfo initialState = *results;
+
+ // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
+ while ( (p < instructionsEnd) && (codeOffset < pcoffset) ) {
+ uint64_t reg;
+ uint64_t reg2;
+ int64_t offset;
+ uint64_t length;
+ uint8_t opcode = addressSpace.get8(p);
+ uint8_t operand;
+ PrologInfoStackEntry* entry;
+ ++p;
+ switch (opcode) {
+ case DW_CFA_nop:
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_nop\n");
+ break;
+ case DW_CFA_set_loc:
+ codeOffset = addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_set_loc\n");
+ break;
+ case DW_CFA_advance_loc1:
+ codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
+ p += 1;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc1: new offset=%u\n", codeOffset);
+ break;
+ case DW_CFA_advance_loc2:
+ codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
+ p += 2;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc2: new offset=%u\n", codeOffset);
+ break;
+ case DW_CFA_advance_loc4:
+ codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
+ p += 4;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc4: new offset=%u\n", codeOffset);
+ break;
+ case DW_CFA_offset_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
+ return false;
+ }
+ if ( results->savedRegisters[reg].location != kRegisterUnused )
+ results->registerSavedMoreThanOnce = true;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_restore_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);;
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg] = initialState.savedRegisters[reg];
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_extended(reg=%lld)\n", reg);
+ break;
+ case DW_CFA_undefined:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_undefined dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterUnused;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_undefined(reg=%lld)\n", reg);
+ break;
+ case DW_CFA_same_value:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_same_value dwarf unwind, reg too big\n");
+ return false;
+ }
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_same_value(reg=%lld)\n", reg);
+ break;
+ case DW_CFA_register:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ reg2 = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg too big\n");
+ return false;
+ }
+ if ( reg2 > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg2 too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterInRegister;
+ results->savedRegisters[reg].value = reg2;
+ results->registersInOtherRegisters = true;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_register(reg=%lld, reg2=%lld)\n", reg, reg2);
+ break;
+ case DW_CFA_remember_state:
+ // avoid operator new, because that would be an upward dependency
+ entry = (PrologInfoStackEntry*)malloc(sizeof(PrologInfoStackEntry));
+ if ( entry != NULL ) {
+ entry->next = rememberStack;
+ entry->info = *results;
+ rememberStack = entry;
+ }
+ else {
+ return false;
+ }
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_remember_state\n");
+ break;
+ case DW_CFA_restore_state:
+ if ( rememberStack != NULL ) {
+ PrologInfoStackEntry* top = rememberStack;
+ *results = top->info;
+ rememberStack = top->next;
+ free((char*)top);
+ }
+ else {
+ return false;
+ }
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_state\n");
+ break;
+ case DW_CFA_def_cfa:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->cfaRegister = reg;
+ results->cfaRegisterOffset = offset;
+ if ( offset > 0x80000000 )
+ results->cfaOffsetWasNegative = true;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_def_cfa_register:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->cfaRegister = reg;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg);
+ break;
+ case DW_CFA_def_cfa_offset:
+ results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd);
+ results->codeOffsetAtStackDecrement = codeOffset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", results->cfaRegisterOffset);
+ break;
+ case DW_CFA_def_cfa_expression:
+ results->cfaRegister = 0;
+ results->cfaExpression = p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ p += length;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n",
+ results->cfaExpression, length);
+ break;
+ case DW_CFA_expression:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_expression dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterAtExpression;
+ results->savedRegisters[reg].value = p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ p += length;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n",
+ reg, results->savedRegisters[reg].value, length);
+ break;
+ case DW_CFA_offset_extended_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
+ return false;
+ }
+ offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( results->savedRegisters[reg].location != kRegisterUnused )
+ results->registerSavedMoreThanOnce = true;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_def_cfa_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->cfaRegister = reg;
+ results->cfaRegisterOffset = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ results->cfaRegisterOffset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ results->codeOffsetAtStackDecrement = codeOffset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", results->cfaRegisterOffset);
+ break;
+ case DW_CFA_val_offset:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset(reg=%lld, offset=%lld\n", reg, offset);
+ break;
+ case DW_CFA_val_offset_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
+ return false;
+ }
+ offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset_sf(reg=%lld, offset=%lld\n", reg, offset);
+ break;
+ case DW_CFA_val_expression:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterIsExpression;
+ results->savedRegisters[reg].value = p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ p += length;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n",
+ reg, results->savedRegisters[reg].value, length);
+ break;
+ case DW_CFA_GNU_args_size:
+ offset = addressSpace.getULEB128(p, instructionsEnd);
+ results->spExtraArgSize = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_args_size(%lld)\n", offset);
+ break;
+ case DW_CFA_GNU_negative_offset_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if ( reg > kMaxRegisterNumber ) {
+ fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf unwind, reg too big\n");
+ return false;
+ }
+ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( results->savedRegisters[reg].location != kRegisterUnused )
+ results->registerSavedMoreThanOnce = true;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = -offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%lld)\n", offset);
+ break;
+ default:
+ operand = opcode & 0x3F;
+ switch ( opcode & 0xC0 ) {
+ case DW_CFA_offset:
+ reg = operand;
+ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if ( results->savedRegisters[reg].location != kRegisterUnused )
+ results->registerSavedMoreThanOnce = true;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = offset;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%lld)\n", operand, offset);
+ break;
+ case DW_CFA_advance_loc:
+ codeOffset += operand * cieInfo.codeAlignFactor;
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc: new offset=%u\n", codeOffset);
+ break;
+ case DW_CFA_restore:
+ // <rdar://problem/7503075> Python crashes when handling an exception thrown by an obj-c object
+ // libffi uses DW_CFA_restore in the middle of some custom dward, so it is not a good epilog flag
+ //return true; // gcc-4.5 starts the epilog with this
+ reg = operand;
+ results->savedRegisters[reg] = initialState.savedRegisters[reg];
+ if ( logDwarf ) fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg);
+ break;
+ default:
+ if ( logDwarf ) fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+} // namespace lldb_private
+
+
+#endif // __DWARF_PARSER_HPP__
+
+
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/FileAbstraction.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/FileAbstraction.hpp
new file mode 100644
index 00000000000..a4af02051a5
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/FileAbstraction.hpp
@@ -0,0 +1,135 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- FileAbstraction.hpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __FILE_ABSTRACTION__
+#define __FILE_ABSTRACTION__
+
+
+#include <stdint.h>
+#include <string.h>
+#include <libkern/OSByteOrder.h>
+
+#ifdef __OPTIMIZE__
+#define INLINE __attribute__((always_inline))
+#else
+#define INLINE
+#endif
+
+//
+// This abstraction layer is for use with file formats that have 64-bit/32-bit and Big-Endian/Little-Endian variants
+//
+// For example: to make a utility that handles 32-bit little enidan files use: Pointer32<LittleEndian>
+//
+//
+// get16() read a 16-bit number from an E endian struct
+// set16() write a 16-bit number to an E endian struct
+// get32() read a 32-bit number from an E endian struct
+// set32() write a 32-bit number to an E endian struct
+// get64() read a 64-bit number from an E endian struct
+// set64() write a 64-bit number to an E endian struct
+//
+// getBits() read a bit field from an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
+// setBits() write a bit field to an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
+//
+// getBitsRaw() read a bit field from a struct with native endianness
+// setBitsRaw() write a bit field from a struct with native endianness
+//
+
+class BigEndian
+{
+public:
+ static uint16_t get16(const uint16_t& from) INLINE { return OSReadBigInt16(&from, 0); }
+ static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteBigInt16(&into, 0, value); }
+
+ static uint32_t get32(const uint32_t& from) INLINE { return OSReadBigInt32(&from, 0); }
+ static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteBigInt32(&into, 0, value); }
+
+ static uint64_t get64(const uint64_t& from) INLINE { return OSReadBigInt64(&from, 0); }
+ static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteBigInt64(&into, 0, value); }
+
+ static uint32_t getBits(const uint32_t& from,
+ uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
+ static void setBits(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
+
+ static uint32_t getBitsRaw(const uint32_t& from,
+ uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> (32-firstBit-bitCount)) & ((1<<bitCount)-1)); }
+ static void setBitsRaw(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
+ const uint32_t mask = ((1<<bitCount)-1);
+ temp &= ~(mask << (32-firstBit-bitCount));
+ temp |= ((value & mask) << (32-firstBit-bitCount));
+ into = temp; }
+ enum { little_endian = 0 };
+};
+
+
+class LittleEndian
+{
+public:
+ static uint16_t get16(const uint16_t& from) INLINE { return OSReadLittleInt16(&from, 0); }
+ static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteLittleInt16(&into, 0, value); }
+
+ static uint32_t get32(const uint32_t& from) INLINE { return OSReadLittleInt32(&from, 0); }
+ static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteLittleInt32(&into, 0, value); }
+
+ static uint64_t get64(const uint64_t& from) INLINE { return OSReadLittleInt64(&from, 0); }
+ static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteLittleInt64(&into, 0, value); }
+
+ static uint32_t getBits(const uint32_t& from,
+ uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
+ static void setBits(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
+
+ static uint32_t getBitsRaw(const uint32_t& from,
+ uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> firstBit) & ((1<<bitCount)-1)); }
+ static void setBitsRaw(uint32_t& into, uint32_t value,
+ uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
+ const uint32_t mask = ((1<<bitCount)-1);
+ temp &= ~(mask << firstBit);
+ temp |= ((value & mask) << firstBit);
+ into = temp; }
+ enum { little_endian = 1 };
+};
+
+
+template <typename _E>
+class Pointer32
+{
+public:
+ typedef uint32_t uint_t;
+ typedef int32_t int_t;
+ typedef _E E;
+
+ static uint64_t getP(const uint_t& from) INLINE { return _E::get32(from); }
+ static void setP(uint_t& into, uint64_t value) INLINE { _E::set32(into, value); }
+};
+
+
+template <typename _E>
+class Pointer64
+{
+public:
+ typedef uint64_t uint_t;
+ typedef int64_t int_t;
+ typedef _E E;
+
+ static uint64_t getP(const uint_t& from) INLINE { return _E::get64(from); }
+ static void setP(uint_t& into, uint64_t value) INLINE { _E::set64(into, value); }
+};
+
+
+
+
+
+
+#endif // __FILE_ABSTRACTION__
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/InternalMacros.h b/lldb/source/Plugins/Process/Utility/libunwind/src/InternalMacros.h
new file mode 100644
index 00000000000..40483900d38
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/InternalMacros.h
@@ -0,0 +1,89 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- InternalMacros.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef INTERNAL_MACROS_H
+#define INTERNAL_MACROS_H
+
+#include <assert.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern void __assert_rtn(const char *, const char *, int, const char *) __attribute__((noreturn));
+#ifdef __cplusplus
+}
+#endif
+
+#define UNW_STEP_SUCCESS 1
+#define UNW_STEP_END 0
+
+
+struct v128 { unsigned int vec[4]; };
+
+
+#define EXPORT __attribute__((visibility("default")))
+
+#define COMPILE_TIME_ASSERT( expr ) \
+ extern int compile_time_assert_failed[ ( expr ) ? 1 : -1 ] __attribute__( ( unused ) );
+
+#define ABORT(msg) __assert_rtn(__func__, __FILE__, __LINE__, msg)
+
+#if NDEBUG
+ #define DEBUG_MESSAGE(msg, ...)
+ #define DEBUG_PRINT_API(msg, ...)
+ #define DEBUG_PRINT_UNWINDING_TEST 0
+ #define DEBUG_PRINT_UNWINDING(msg, ...)
+ #define DEBUG_LOG_NON_ZERO(x) x;
+ #define INITIALIZE_DEBUG_PRINT_API
+ #define INITIALIZE_DEBUG_PRINT_UNWINDING
+#else
+ #define DEBUG_MESSAGE(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__)
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ extern bool logAPIs();
+ extern bool logUnwinding();
+ #ifdef __cplusplus
+ }
+ #endif
+ #define DEBUG_LOG_NON_ZERO(x) { int _err = x; if ( _err != 0 ) fprintf(stderr, "libuwind: " #x "=%d in %s", _err, __FUNCTION__); }
+ #define DEBUG_PRINT_API(msg, ...) do { if ( logAPIs() ) fprintf(stderr, msg, __VA_ARGS__); } while(0)
+ #define DEBUG_PRINT_UNWINDING(msg, ...) do { if ( logUnwinding() ) fprintf(stderr, msg, __VA_ARGS__); } while(0)
+ #define DEBUG_PRINT_UNWINDING_TEST logUnwinding()
+ #define INITIALIZE_DEBUG_PRINT_API bool logAPIs() { static bool log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); return log; }
+ #define INITIALIZE_DEBUG_PRINT_UNWINDING bool logUnwinding() { static bool log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); return log; }
+#endif
+
+
+// note hack for <rdar://problem/6175741>
+// Once libgcc_s.dylib vectors to libSystem, then we can remove the $ld$hide$os10.6$ lines
+#if __ppc__
+ #define NOT_HERE_BEFORE_10_6(sym) \
+ extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+ #define NEVER_HERE(sym) \
+ extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+#else
+ #define NOT_HERE_BEFORE_10_6(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+ #define NEVER_HERE(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+#endif
+
+
+
+#endif // INTERNAL_MACROS_H
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/Registers.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/Registers.hpp
new file mode 100644
index 00000000000..291c72425d4
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/Registers.hpp
@@ -0,0 +1,985 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- Registers.hpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//
+// C++ interface to lower levels of libuwind
+//
+
+#ifndef __REGISTERS_HPP__
+#define __REGISTERS_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <mach-o/loader.h>
+#include <mach-o/getsect.h>
+#include <mach/ppc/thread_status.h>
+#include <mach/i386/thread_status.h>
+
+#include "libunwind.h"
+#include "InternalMacros.h"
+
+namespace lldb_private {
+
+
+///
+/// Registers_x86 holds the register state of a thread in a 32-bit intel process.
+///
+class Registers_x86
+{
+public:
+ Registers_x86();
+ Registers_x86(const void* registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num) const;
+ void setRegister(int num, uint32_t value);
+ bool validFloatRegister(int num) const { return false; }
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const { return false; }
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char* getRegisterName(int num);
+ void jumpto() {}
+
+ uint32_t getSP() const { return fRegisters.__esp; }
+ void setSP(uint32_t value) { fRegisters.__esp = value; }
+ uint32_t getIP() const { return fRegisters.__eip; }
+ void setIP(uint32_t value) { fRegisters.__eip = value; }
+ uint32_t getEBP() const { return fRegisters.__ebp; }
+ void setEBP(uint32_t value) { fRegisters.__ebp = value; }
+ uint32_t getEBX() const { return fRegisters.__ebx; }
+ void setEBX(uint32_t value) { fRegisters.__ebx = value; }
+ uint32_t getECX() const { return fRegisters.__ecx; }
+ void setECX(uint32_t value) { fRegisters.__ecx = value; }
+ uint32_t getEDX() const { return fRegisters.__edx; }
+ void setEDX(uint32_t value) { fRegisters.__edx = value; }
+ uint32_t getESI() const { return fRegisters.__esi; }
+ void setESI(uint32_t value) { fRegisters.__esi = value; }
+ uint32_t getEDI() const { return fRegisters.__edi; }
+ void setEDI(uint32_t value) { fRegisters.__edi = value; }
+
+private:
+ i386_thread_state_t fRegisters;
+};
+
+inline Registers_x86::Registers_x86(const void* registers)
+{
+ COMPILE_TIME_ASSERT( sizeof(Registers_x86) < sizeof(unw_context_t) );
+ fRegisters = *((i386_thread_state_t*)registers);
+}
+
+inline Registers_x86::Registers_x86()
+{
+ bzero(&fRegisters, sizeof(fRegisters));
+}
+
+
+inline bool Registers_x86::validRegister(int regNum) const
+{
+ if ( regNum == UNW_REG_IP )
+ return true;
+ if ( regNum == UNW_REG_SP )
+ return true;
+ if ( regNum < 0 )
+ return false;
+ if ( regNum > 7 )
+ return false;
+ return true;
+}
+
+inline uint32_t Registers_x86::getRegister(int regNum) const
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return fRegisters.__eip;
+ case UNW_REG_SP:
+ return fRegisters.__esp;
+ case UNW_X86_EAX:
+ return fRegisters.__eax;
+ case UNW_X86_ECX:
+ return fRegisters.__ecx;
+ case UNW_X86_EDX:
+ return fRegisters.__edx;
+ case UNW_X86_EBX:
+ return fRegisters.__ebx;
+ case UNW_X86_EBP:
+ return fRegisters.__ebp;
+ case UNW_X86_ESP:
+ return fRegisters.__esp;
+ case UNW_X86_ESI:
+ return fRegisters.__esi;
+ case UNW_X86_EDI:
+ return fRegisters.__edi;
+ }
+ ABORT("unsupported x86 register");
+}
+
+inline void Registers_x86::setRegister(int regNum, uint32_t value)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ fRegisters.__eip = value;
+ return;
+ case UNW_REG_SP:
+ fRegisters.__esp = value;
+ return;
+ case UNW_X86_EAX:
+ fRegisters.__eax = value;
+ return;
+ case UNW_X86_ECX:
+ fRegisters.__ecx = value;
+ return;
+ case UNW_X86_EDX:
+ fRegisters.__edx = value;
+ return;
+ case UNW_X86_EBX:
+ fRegisters.__ebx = value;
+ return;
+ case UNW_X86_EBP:
+ fRegisters.__ebp = value;
+ return;
+ case UNW_X86_ESP:
+ fRegisters.__esp = value;
+ return;
+ case UNW_X86_ESI:
+ fRegisters.__esi = value;
+ return;
+ case UNW_X86_EDI:
+ fRegisters.__edi = value;
+ return;
+ }
+ ABORT("unsupported x86 register");
+}
+
+inline const char* Registers_x86::getRegisterName(int regNum)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return "ip";
+ case UNW_REG_SP:
+ return "esp";
+ case UNW_X86_EAX:
+ return "eax";
+ case UNW_X86_ECX:
+ return "ecx";
+ case UNW_X86_EDX:
+ return "edx";
+ case UNW_X86_EBX:
+ return "ebx";
+ case UNW_X86_EBP:
+ return "ebp";
+ case UNW_X86_ESP:
+ return "esp";
+ case UNW_X86_ESI:
+ return "esi";
+ case UNW_X86_EDI:
+ return "edi";
+ default:
+ return "unknown register";
+ }
+}
+
+inline double Registers_x86::getFloatRegister(int num) const
+{
+ ABORT("no x86 float registers");
+}
+
+inline void Registers_x86::setFloatRegister(int num, double value)
+{
+ ABORT("no x86 float registers");
+}
+
+inline v128 Registers_x86::getVectorRegister(int num) const
+{
+ ABORT("no x86 vector registers");
+}
+
+inline void Registers_x86::setVectorRegister(int num, v128 value)
+{
+ ABORT("no x86 vector registers");
+}
+
+
+
+
+///
+/// Registers_x86_64 holds the register state of a thread in a 64-bit intel process.
+///
+class Registers_x86_64
+{
+public:
+ Registers_x86_64();
+ Registers_x86_64(const void* registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int num) const{ return false; }
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const { return false; }
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char* getRegisterName(int num);
+ void jumpto() {}
+ uint64_t getSP() const { return fRegisters.__rsp; }
+ void setSP(uint64_t value) { fRegisters.__rsp = value; }
+ uint64_t getIP() const { return fRegisters.__rip; }
+ void setIP(uint64_t value) { fRegisters.__rip = value; }
+ uint64_t getRBP() const { return fRegisters.__rbp; }
+ void setRBP(uint64_t value) { fRegisters.__rbp = value; }
+ uint64_t getRBX() const { return fRegisters.__rbx; }
+ void setRBX(uint64_t value) { fRegisters.__rbx = value; }
+ uint64_t getR12() const { return fRegisters.__r12; }
+ void setR12(uint64_t value) { fRegisters.__r12 = value; }
+ uint64_t getR13() const { return fRegisters.__r13; }
+ void setR13(uint64_t value) { fRegisters.__r13 = value; }
+ uint64_t getR14() const { return fRegisters.__r14; }
+ void setR14(uint64_t value) { fRegisters.__r14 = value; }
+ uint64_t getR15() const { return fRegisters.__r15; }
+ void setR15(uint64_t value) { fRegisters.__r15 = value; }
+private:
+ x86_thread_state64_t fRegisters;
+};
+
+inline Registers_x86_64::Registers_x86_64(const void* registers)
+{
+ COMPILE_TIME_ASSERT( sizeof(Registers_x86_64) < sizeof(unw_context_t) );
+ fRegisters = *((x86_thread_state64_t*)registers);
+}
+
+inline Registers_x86_64::Registers_x86_64()
+{
+ bzero(&fRegisters, sizeof(fRegisters));
+}
+
+
+inline bool Registers_x86_64::validRegister(int regNum) const
+{
+ if ( regNum == UNW_REG_IP )
+ return true;
+ if ( regNum == UNW_REG_SP )
+ return true;
+ if ( regNum < 0 )
+ return false;
+ if ( regNum > 15 )
+ return false;
+ return true;
+}
+
+inline uint64_t Registers_x86_64::getRegister(int regNum) const
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return fRegisters.__rip;
+ case UNW_REG_SP:
+ return fRegisters.__rsp;
+ case UNW_X86_64_RAX:
+ return fRegisters.__rax;
+ case UNW_X86_64_RDX:
+ return fRegisters.__rdx;
+ case UNW_X86_64_RCX:
+ return fRegisters.__rcx;
+ case UNW_X86_64_RBX:
+ return fRegisters.__rbx;
+ case UNW_X86_64_RSI:
+ return fRegisters.__rsi;
+ case UNW_X86_64_RDI:
+ return fRegisters.__rdi;
+ case UNW_X86_64_RBP:
+ return fRegisters.__rbp;
+ case UNW_X86_64_RSP:
+ return fRegisters.__rsp;
+ case UNW_X86_64_R8:
+ return fRegisters.__r8;
+ case UNW_X86_64_R9:
+ return fRegisters.__r9;
+ case UNW_X86_64_R10:
+ return fRegisters.__r10;
+ case UNW_X86_64_R11:
+ return fRegisters.__r11;
+ case UNW_X86_64_R12:
+ return fRegisters.__r12;
+ case UNW_X86_64_R13:
+ return fRegisters.__r13;
+ case UNW_X86_64_R14:
+ return fRegisters.__r14;
+ case UNW_X86_64_R15:
+ return fRegisters.__r15;
+ }
+ ABORT("unsupported x86_64 register");
+}
+
+inline void Registers_x86_64::setRegister(int regNum, uint64_t value)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ fRegisters.__rip = value;
+ return;
+ case UNW_REG_SP:
+ fRegisters.__rsp = value;
+ return;
+ case UNW_X86_64_RAX:
+ fRegisters.__rax = value;
+ return;
+ case UNW_X86_64_RDX:
+ fRegisters.__rdx = value;
+ return;
+ case UNW_X86_64_RCX:
+ fRegisters.__rcx = value;
+ return;
+ case UNW_X86_64_RBX:
+ fRegisters.__rbx = value;
+ return;
+ case UNW_X86_64_RSI:
+ fRegisters.__rsi = value;
+ return;
+ case UNW_X86_64_RDI:
+ fRegisters.__rdi = value;
+ return;
+ case UNW_X86_64_RBP:
+ fRegisters.__rbp = value;
+ return;
+ case UNW_X86_64_RSP:
+ fRegisters.__rsp = value;
+ return;
+ case UNW_X86_64_R8:
+ fRegisters.__r8 = value;
+ return;
+ case UNW_X86_64_R9:
+ fRegisters.__r9 = value;
+ return;
+ case UNW_X86_64_R10:
+ fRegisters.__r10 = value;
+ return;
+ case UNW_X86_64_R11:
+ fRegisters.__r11 = value;
+ return;
+ case UNW_X86_64_R12:
+ fRegisters.__r12 = value;
+ return;
+ case UNW_X86_64_R13:
+ fRegisters.__r13 = value;
+ return;
+ case UNW_X86_64_R14:
+ fRegisters.__r14 = value;
+ return;
+ case UNW_X86_64_R15:
+ fRegisters.__r15 = value;
+ return;
+ }
+ ABORT("unsupported x86_64 register");
+}
+
+inline const char* Registers_x86_64::getRegisterName(int regNum)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return "rip";
+ case UNW_REG_SP:
+ return "rsp";
+ case UNW_X86_64_RAX:
+ return "rax";
+ case UNW_X86_64_RDX:
+ return "rdx";
+ case UNW_X86_64_RCX:
+ return "rcx";
+ case UNW_X86_64_RBX:
+ return "rbx";
+ case UNW_X86_64_RSI:
+ return "rsi";
+ case UNW_X86_64_RDI:
+ return "rdi";
+ case UNW_X86_64_RBP:
+ return "rbp";
+ case UNW_X86_64_RSP:
+ return "rsp";
+ case UNW_X86_64_R8:
+ return "r8";
+ case UNW_X86_64_R9:
+ return "r9";
+ case UNW_X86_64_R10:
+ return "r10";
+ case UNW_X86_64_R11:
+ return "r11";
+ case UNW_X86_64_R12:
+ return "r12";
+ case UNW_X86_64_R13:
+ return "r13";
+ case UNW_X86_64_R14:
+ return "r14";
+ case UNW_X86_64_R15:
+ return "r15";
+ default:
+ return "unknown register";
+ }
+}
+
+double Registers_x86_64::getFloatRegister(int num) const
+{
+ ABORT("no x86_64 float registers");
+}
+
+void Registers_x86_64::setFloatRegister(int num, double value)
+{
+ ABORT("no x86_64 float registers");
+}
+
+inline v128 Registers_x86_64::getVectorRegister(int num) const
+{
+ ABORT("no x86_64 vector registers");
+}
+
+inline void Registers_x86_64::setVectorRegister(int num, v128 value)
+{
+ ABORT("no x86_64 vector registers");
+}
+
+
+///
+/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC process.
+///
+class Registers_ppc
+{
+public:
+ Registers_ppc();
+ Registers_ppc(const void* registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num) const;
+ void setRegister(int num, uint32_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ void jumpto() {}
+ const char* getRegisterName(int num);
+ uint64_t getSP() const { return fRegisters.__r1; }
+ void setSP(uint64_t value) { fRegisters.__r1 = value; }
+ uint64_t getIP() const { return fRegisters.__srr0; }
+ void setIP(uint64_t value) { fRegisters.__srr0 = value; }
+private:
+ ppc_thread_state_t fRegisters;
+ ppc_float_state_t fFloatRegisters;
+ v128 fVectorRegisters[32]; // offset 424
+};
+
+
+
+inline Registers_ppc::Registers_ppc(const void* registers)
+{
+ COMPILE_TIME_ASSERT( sizeof(Registers_ppc) < sizeof(unw_context_t) );
+ fRegisters = *((ppc_thread_state_t*)registers);
+ fFloatRegisters = *((ppc_float_state_t*)((char*)registers+160));
+ memcpy(fVectorRegisters, ((char*)registers+424), sizeof(fVectorRegisters));
+}
+
+inline Registers_ppc::Registers_ppc()
+{
+ bzero(&fRegisters, sizeof(fRegisters));
+ bzero(&fFloatRegisters, sizeof(fFloatRegisters));
+ bzero(&fVectorRegisters, sizeof(fVectorRegisters));
+}
+
+
+inline bool Registers_ppc::validRegister(int regNum) const
+{
+ if ( regNum == UNW_REG_IP )
+ return true;
+ if ( regNum == UNW_REG_SP )
+ return true;
+ if ( regNum == UNW_PPC_VRSAVE )
+ return true;
+ if ( regNum < 0 )
+ return false;
+ if ( regNum <= UNW_PPC_R31 )
+ return true;
+ if ( regNum == UNW_PPC_MQ )
+ return true;
+ if ( regNum == UNW_PPC_LR )
+ return true;
+ if ( regNum == UNW_PPC_CTR )
+ return true;
+ if ( (UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7) )
+ return true;
+ return false;
+}
+
+
+inline uint32_t Registers_ppc::getRegister(int regNum) const
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return fRegisters.__srr0;
+ case UNW_REG_SP:
+ return fRegisters.__r1;
+ case UNW_PPC_R0:
+ return fRegisters.__r0;
+ case UNW_PPC_R1:
+ return fRegisters.__r1;
+ case UNW_PPC_R2:
+ return fRegisters.__r2;
+ case UNW_PPC_R3:
+ return fRegisters.__r3;
+ case UNW_PPC_R4:
+ return fRegisters.__r4;
+ case UNW_PPC_R5:
+ return fRegisters.__r5;
+ case UNW_PPC_R6:
+ return fRegisters.__r6;
+ case UNW_PPC_R7:
+ return fRegisters.__r7;
+ case UNW_PPC_R8:
+ return fRegisters.__r8;
+ case UNW_PPC_R9:
+ return fRegisters.__r9;
+ case UNW_PPC_R10:
+ return fRegisters.__r10;
+ case UNW_PPC_R11:
+ return fRegisters.__r11;
+ case UNW_PPC_R12:
+ return fRegisters.__r12;
+ case UNW_PPC_R13:
+ return fRegisters.__r13;
+ case UNW_PPC_R14:
+ return fRegisters.__r14;
+ case UNW_PPC_R15:
+ return fRegisters.__r15;
+ case UNW_PPC_R16:
+ return fRegisters.__r16;
+ case UNW_PPC_R17:
+ return fRegisters.__r17;
+ case UNW_PPC_R18:
+ return fRegisters.__r18;
+ case UNW_PPC_R19:
+ return fRegisters.__r19;
+ case UNW_PPC_R20:
+ return fRegisters.__r20;
+ case UNW_PPC_R21:
+ return fRegisters.__r21;
+ case UNW_PPC_R22:
+ return fRegisters.__r22;
+ case UNW_PPC_R23:
+ return fRegisters.__r23;
+ case UNW_PPC_R24:
+ return fRegisters.__r24;
+ case UNW_PPC_R25:
+ return fRegisters.__r25;
+ case UNW_PPC_R26:
+ return fRegisters.__r26;
+ case UNW_PPC_R27:
+ return fRegisters.__r27;
+ case UNW_PPC_R28:
+ return fRegisters.__r28;
+ case UNW_PPC_R29:
+ return fRegisters.__r29;
+ case UNW_PPC_R30:
+ return fRegisters.__r30;
+ case UNW_PPC_R31:
+ return fRegisters.__r31;
+ case UNW_PPC_LR:
+ return fRegisters.__lr;
+ case UNW_PPC_CR0:
+ return (fRegisters.__cr & 0xF0000000);
+ case UNW_PPC_CR1:
+ return (fRegisters.__cr & 0x0F000000);
+ case UNW_PPC_CR2:
+ return (fRegisters.__cr & 0x00F00000);
+ case UNW_PPC_CR3:
+ return (fRegisters.__cr & 0x000F0000);
+ case UNW_PPC_CR4:
+ return (fRegisters.__cr & 0x0000F000);
+ case UNW_PPC_CR5:
+ return (fRegisters.__cr & 0x00000F00);
+ case UNW_PPC_CR6:
+ return (fRegisters.__cr & 0x000000F0);
+ case UNW_PPC_CR7:
+ return (fRegisters.__cr & 0x0000000F);
+ case UNW_PPC_VRSAVE:
+ return fRegisters.__vrsave;
+ }
+ ABORT("unsupported ppc register");
+}
+
+
+inline void Registers_ppc::setRegister(int regNum, uint32_t value)
+{
+ //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value);
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ fRegisters.__srr0 = value;
+ return;
+ case UNW_REG_SP:
+ fRegisters.__r1 = value;
+ return;
+ case UNW_PPC_R0:
+ fRegisters.__r0 = value;
+ return;
+ case UNW_PPC_R1:
+ fRegisters.__r1 = value;
+ return;
+ case UNW_PPC_R2:
+ fRegisters.__r2 = value;
+ return;
+ case UNW_PPC_R3:
+ fRegisters.__r3 = value;
+ return;
+ case UNW_PPC_R4:
+ fRegisters.__r4 = value;
+ return;
+ case UNW_PPC_R5:
+ fRegisters.__r5 = value;
+ return;
+ case UNW_PPC_R6:
+ fRegisters.__r6 = value;
+ return;
+ case UNW_PPC_R7:
+ fRegisters.__r7 = value;
+ return;
+ case UNW_PPC_R8:
+ fRegisters.__r8 = value;
+ return;
+ case UNW_PPC_R9:
+ fRegisters.__r9 = value;
+ return;
+ case UNW_PPC_R10:
+ fRegisters.__r10 = value;
+ return;
+ case UNW_PPC_R11:
+ fRegisters.__r11 = value;
+ return;
+ case UNW_PPC_R12:
+ fRegisters.__r12 = value;
+ return;
+ case UNW_PPC_R13:
+ fRegisters.__r13 = value;
+ return;
+ case UNW_PPC_R14:
+ fRegisters.__r14 = value;
+ return;
+ case UNW_PPC_R15:
+ fRegisters.__r15 = value;
+ return;
+ case UNW_PPC_R16:
+ fRegisters.__r16 = value;
+ return;
+ case UNW_PPC_R17:
+ fRegisters.__r17 = value;
+ return;
+ case UNW_PPC_R18:
+ fRegisters.__r18 = value;
+ return;
+ case UNW_PPC_R19:
+ fRegisters.__r19 = value;
+ return;
+ case UNW_PPC_R20:
+ fRegisters.__r20 = value;
+ return;
+ case UNW_PPC_R21:
+ fRegisters.__r21 = value;
+ return;
+ case UNW_PPC_R22:
+ fRegisters.__r22 = value;
+ return;
+ case UNW_PPC_R23:
+ fRegisters.__r23 = value;
+ return;
+ case UNW_PPC_R24:
+ fRegisters.__r24 = value;
+ return;
+ case UNW_PPC_R25:
+ fRegisters.__r25 = value;
+ return;
+ case UNW_PPC_R26:
+ fRegisters.__r26 = value;
+ return;
+ case UNW_PPC_R27:
+ fRegisters.__r27 = value;
+ return;
+ case UNW_PPC_R28:
+ fRegisters.__r28 = value;
+ return;
+ case UNW_PPC_R29:
+ fRegisters.__r29 = value;
+ return;
+ case UNW_PPC_R30:
+ fRegisters.__r30 = value;
+ return;
+ case UNW_PPC_R31:
+ fRegisters.__r31 = value;
+ return;
+ case UNW_PPC_MQ:
+ fRegisters.__mq = value;
+ return;
+ case UNW_PPC_LR:
+ fRegisters.__lr = value;
+ return;
+ case UNW_PPC_CTR:
+ fRegisters.__ctr = value;
+ return;
+ case UNW_PPC_CR0:
+ fRegisters.__cr &= 0x0FFFFFFF;
+ fRegisters.__cr |= (value & 0xF0000000);
+ return;
+ case UNW_PPC_CR1:
+ fRegisters.__cr &= 0xF0FFFFFF;
+ fRegisters.__cr |= (value & 0x0F000000);
+ return;
+ case UNW_PPC_CR2:
+ fRegisters.__cr &= 0xFF0FFFFF;
+ fRegisters.__cr |= (value & 0x00F00000);
+ return;
+ case UNW_PPC_CR3:
+ fRegisters.__cr &= 0xFFF0FFFF;
+ fRegisters.__cr |= (value & 0x000F0000);
+ return;
+ case UNW_PPC_CR4:
+ fRegisters.__cr &= 0xFFFF0FFF;
+ fRegisters.__cr |= (value & 0x0000F000);
+ return;
+ case UNW_PPC_CR5:
+ fRegisters.__cr &= 0xFFFFF0FF;
+ fRegisters.__cr |= (value & 0x00000F00);
+ return;
+ case UNW_PPC_CR6:
+ fRegisters.__cr &= 0xFFFFFF0F;
+ fRegisters.__cr |= (value & 0x000000F0);
+ return;
+ case UNW_PPC_CR7:
+ fRegisters.__cr &= 0xFFFFFFF0;
+ fRegisters.__cr |= (value & 0x0000000F);
+ return;
+ case UNW_PPC_VRSAVE:
+ fRegisters.__vrsave = value;
+ return;
+ // not saved
+ return;
+ case UNW_PPC_XER:
+ fRegisters.__xer = value;
+ return;
+ case UNW_PPC_AP:
+ case UNW_PPC_VSCR:
+ case UNW_PPC_SPEFSCR:
+ // not saved
+ return;
+ }
+ ABORT("unsupported ppc register");
+}
+
+inline bool Registers_ppc::validFloatRegister(int regNum) const
+{
+ if ( regNum < UNW_PPC_F0 )
+ return false;
+ if ( regNum > UNW_PPC_F31 )
+ return false;
+ return true;
+}
+
+inline double Registers_ppc::getFloatRegister(int regNum) const
+{
+ assert(validFloatRegister(regNum));
+ return fFloatRegisters.__fpregs[regNum-UNW_PPC_F0];
+}
+
+inline void Registers_ppc::setFloatRegister(int regNum, double value)
+{
+ //fprintf(stderr, "Registers_ppc::setFloatRegister(%d, %g))\n", regNum, value);
+ assert(validFloatRegister(regNum));
+ fFloatRegisters.__fpregs[regNum-UNW_PPC_F0] = value;
+}
+
+
+inline bool Registers_ppc::validVectorRegister(int regNum) const
+{
+ if ( regNum < UNW_PPC_V0 )
+ return false;
+ if ( regNum > UNW_PPC_V31 )
+ return false;
+ return true;
+}
+
+v128 Registers_ppc::getVectorRegister(int regNum) const
+{
+ assert(validVectorRegister(regNum));
+ v128 result = fVectorRegisters[regNum-UNW_PPC_V0];
+ //fprintf(stderr, "Registers_ppc::getVectorRegister(this=%p, %d) => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n",
+ // this, regNum, result.vec[0], result.vec[1], result.vec[2], result.vec[3]);
+ return result;
+}
+
+void Registers_ppc::setVectorRegister(int regNum, v128 value)
+{
+ assert(validVectorRegister(regNum));
+ //fprintf(stderr, "Registers_ppc::setVectorRegister(this=%p, %d) <0x%08X, 0x%08X, 0x%08X, 0x%08X> => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n",
+ // this, regNum, fVectorRegisters[regNum-UNW_PPC_V0].vec[0], fVectorRegisters[regNum-UNW_PPC_V0].vec[1], fVectorRegisters[regNum-UNW_PPC_V0].vec[2],
+ // fVectorRegisters[regNum-UNW_PPC_V0].vec[3], value.vec[0], value.vec[1], value.vec[2], value.vec[3]);
+ fVectorRegisters[regNum-UNW_PPC_V0] = value;
+}
+
+
+inline const char* Registers_ppc::getRegisterName(int regNum)
+{
+ switch ( regNum ) {
+ case UNW_REG_IP:
+ return "ip";
+ case UNW_REG_SP:
+ return "sp";
+ case UNW_PPC_R0:
+ return "r0";
+ case UNW_PPC_R1:
+ return "r1";
+ case UNW_PPC_R2:
+ return "r2";
+ case UNW_PPC_R3:
+ return "r3";
+ case UNW_PPC_R4:
+ return "r4";
+ case UNW_PPC_R5:
+ return "r5";
+ case UNW_PPC_R6:
+ return "r6";
+ case UNW_PPC_R7:
+ return "r7";
+ case UNW_PPC_R8:
+ return "r8";
+ case UNW_PPC_R9:
+ return "r9";
+ case UNW_PPC_R10:
+ return "r10";
+ case UNW_PPC_R11:
+ return "r11";
+ case UNW_PPC_R12:
+ return "r12";
+ case UNW_PPC_R13:
+ return "r13";
+ case UNW_PPC_R14:
+ return "r14";
+ case UNW_PPC_R15:
+ return "r15";
+ case UNW_PPC_R16:
+ return "r16";
+ case UNW_PPC_R17:
+ return "r17";
+ case UNW_PPC_R18:
+ return "r18";
+ case UNW_PPC_R19:
+ return "r19";
+ case UNW_PPC_R20:
+ return "r20";
+ case UNW_PPC_R21:
+ return "r21";
+ case UNW_PPC_R22:
+ return "r22";
+ case UNW_PPC_R23:
+ return "r23";
+ case UNW_PPC_R24:
+ return "r24";
+ case UNW_PPC_R25:
+ return "r25";
+ case UNW_PPC_R26:
+ return "r26";
+ case UNW_PPC_R27:
+ return "r27";
+ case UNW_PPC_R28:
+ return "r28";
+ case UNW_PPC_R29:
+ return "r29";
+ case UNW_PPC_R30:
+ return "r30";
+ case UNW_PPC_R31:
+ return "r31";
+ case UNW_PPC_F0:
+ return "fp0";
+ case UNW_PPC_F1:
+ return "fp1";
+ case UNW_PPC_F2:
+ return "fp2";
+ case UNW_PPC_F3:
+ return "fp3";
+ case UNW_PPC_F4:
+ return "fp4";
+ case UNW_PPC_F5:
+ return "fp5";
+ case UNW_PPC_F6:
+ return "fp6";
+ case UNW_PPC_F7:
+ return "fp7";
+ case UNW_PPC_F8:
+ return "fp8";
+ case UNW_PPC_F9:
+ return "fp9";
+ case UNW_PPC_F10:
+ return "fp10";
+ case UNW_PPC_F11:
+ return "fp11";
+ case UNW_PPC_F12:
+ return "fp12";
+ case UNW_PPC_F13:
+ return "fp13";
+ case UNW_PPC_F14:
+ return "fp14";
+ case UNW_PPC_F15:
+ return "fp15";
+ case UNW_PPC_F16:
+ return "fp16";
+ case UNW_PPC_F17:
+ return "fp17";
+ case UNW_PPC_F18:
+ return "fp18";
+ case UNW_PPC_F19:
+ return "fp19";
+ case UNW_PPC_F20:
+ return "fp20";
+ case UNW_PPC_F21:
+ return "fp21";
+ case UNW_PPC_F22:
+ return "fp22";
+ case UNW_PPC_F23:
+ return "fp23";
+ case UNW_PPC_F24:
+ return "fp24";
+ case UNW_PPC_F25:
+ return "fp25";
+ case UNW_PPC_F26:
+ return "fp26";
+ case UNW_PPC_F27:
+ return "fp27";
+ case UNW_PPC_F28:
+ return "fp28";
+ case UNW_PPC_F29:
+ return "fp29";
+ case UNW_PPC_F30:
+ return "fp30";
+ case UNW_PPC_F31:
+ return "fp31";
+ case UNW_PPC_LR:
+ return "lr";
+ default:
+ return "unknown register";
+ }
+
+
+}
+
+
+} // namespace lldb_private
+
+
+
+#endif // __REGISTERS_HPP__
+
+
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/Registers.s b/lldb/source/Plugins/Process/Utility/libunwind/src/Registers.s
new file mode 100644
index 00000000000..45dae3bcbfc
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/Registers.s
@@ -0,0 +1,261 @@
+
+
+#if __i386__
+ .text
+ .globl __ZN12lldb_private13Registers_x866jumptoEv
+ .private_extern __ZN12lldb_private13Registers_x866jumptoEv
+__ZN12lldb_private13Registers_x866jumptoEv:
+#
+# void lldb_private::Registers_x86::jumpto()
+#
+# On entry:
+# + +
+# +-----------------------+
+# + thread_state pointer +
+# +-----------------------+
+# + return address +
+# +-----------------------+ <-- SP
+# + +
+ movl 4(%esp), %eax
+ # set up eax and ret on new stack location
+ movl 28(%eax), %edx # edx holds new stack pointer
+ subl $8,%edx
+ movl %edx, 28(%eax)
+ movl 0(%eax), %ebx
+ movl %ebx, 0(%edx)
+ movl 40(%eax), %ebx
+ movl %ebx, 4(%edx)
+ # we now have ret and eax pushed onto where new stack will be
+ # restore all registers
+ movl 4(%eax), %ebx
+ movl 8(%eax), %ecx
+ movl 12(%eax), %edx
+ movl 16(%eax), %edi
+ movl 20(%eax), %esi
+ movl 24(%eax), %ebp
+ movl 28(%eax), %esp
+ # skip ss
+ # skip eflags
+ pop %eax # eax was already pushed on new stack
+ ret # eip was already pushed on new stack
+ # skip cs
+ # skip ds
+ # skip es
+ # skip fs
+ # skip gs
+
+#elif __x86_64__
+
+ .text
+ .globl __ZN12lldb_private16Registers_x86_646jumptoEv
+ .private_extern __ZN12lldb_private16Registers_x86_646jumptoEv
+__ZN12lldb_private16Registers_x86_646jumptoEv:
+#
+# void lldb_private::Registers_x86_64::jumpto()
+#
+# On entry, thread_state pointer is in rdi
+
+ movq 56(%rdi), %rax # rax holds new stack pointer
+ subq $16, %rax
+ movq %rax, 56(%rdi)
+ movq 32(%rdi), %rbx # store new rdi on new stack
+ movq %rbx, 0(%rax)
+ movq 128(%rdi), %rbx # store new rip on new stack
+ movq %rbx, 8(%rax)
+ # restore all registers
+ movq 0(%rdi), %rax
+ movq 8(%rdi), %rbx
+ movq 16(%rdi), %rcx
+ movq 24(%rdi), %rdx
+ # restore rdi later
+ movq 40(%rdi), %rsi
+ movq 48(%rdi), %rbp
+ # restore rsp later
+ movq 64(%rdi), %r8
+ movq 72(%rdi), %r9
+ movq 80(%rdi), %r10
+ movq 88(%rdi), %r11
+ movq 96(%rdi), %r12
+ movq 104(%rdi), %r13
+ movq 112(%rdi), %r14
+ movq 120(%rdi), %r15
+ # skip rflags
+ # skip cs
+ # skip fs
+ # skip gs
+ movq 56(%rdi), %rsp # cut back rsp to new location
+ pop %rdi # rdi was saved here earlier
+ ret # rip was saved here
+
+
+#elif __ppc__
+
+ .text
+ .globl __ZN12lldb_private13Registers_ppc6jumptoEv
+ .private_extern __ZN12lldb_private13Registers_ppc6jumptoEv
+__ZN12lldb_private13Registers_ppc6jumptoEv:
+;
+; void lldb_private::Registers_ppc::jumpto()
+;
+; On entry:
+; thread_state pointer is in r3
+;
+
+ ; restore integral registerrs
+ ; skip r0 for now
+ ; skip r1 for now
+ lwz r2, 16(r3)
+ ; skip r3 for now
+ ; skip r4 for now
+ ; skip r5 for now
+ lwz r6, 32(r3)
+ lwz r7, 36(r3)
+ lwz r8, 40(r3)
+ lwz r9, 44(r3)
+ lwz r10, 48(r3)
+ lwz r11, 52(r3)
+ lwz r12, 56(r3)
+ lwz r13, 60(r3)
+ lwz r14, 64(r3)
+ lwz r15, 68(r3)
+ lwz r16, 72(r3)
+ lwz r17, 76(r3)
+ lwz r18, 80(r3)
+ lwz r19, 84(r3)
+ lwz r20, 88(r3)
+ lwz r21, 92(r3)
+ lwz r22, 96(r3)
+ lwz r23,100(r3)
+ lwz r24,104(r3)
+ lwz r25,108(r3)
+ lwz r26,112(r3)
+ lwz r27,116(r3)
+ lwz r28,120(r3)
+ lwz r29,124(r3)
+ lwz r30,128(r3)
+ lwz r31,132(r3)
+
+ ; restore float registers
+ lfd f0, 160(r3)
+ lfd f1, 168(r3)
+ lfd f2, 176(r3)
+ lfd f3, 184(r3)
+ lfd f4, 192(r3)
+ lfd f5, 200(r3)
+ lfd f6, 208(r3)
+ lfd f7, 216(r3)
+ lfd f8, 224(r3)
+ lfd f9, 232(r3)
+ lfd f10,240(r3)
+ lfd f11,248(r3)
+ lfd f12,256(r3)
+ lfd f13,264(r3)
+ lfd f14,272(r3)
+ lfd f15,280(r3)
+ lfd f16,288(r3)
+ lfd f17,296(r3)
+ lfd f18,304(r3)
+ lfd f19,312(r3)
+ lfd f20,320(r3)
+ lfd f21,328(r3)
+ lfd f22,336(r3)
+ lfd f23,344(r3)
+ lfd f24,352(r3)
+ lfd f25,360(r3)
+ lfd f26,368(r3)
+ lfd f27,376(r3)
+ lfd f28,384(r3)
+ lfd f29,392(r3)
+ lfd f30,400(r3)
+ lfd f31,408(r3)
+
+ ; restore vector registers if any are in use
+ lwz r5,156(r3) ; test VRsave
+ cmpwi r5,0
+ beq Lnovec
+
+ subi r4,r1,16
+ rlwinm r4,r4,0,0,27 ; mask low 4-bits
+ ; r4 is now a 16-byte aligned pointer into the red zone
+ ; the fVectorRegisters may not be 16-byte aligned so copy via red zone temp buffer
+
+
+#define LOAD_VECTOR_UNALIGNEDl(_index) \
+ andis. r0,r5,(1<<(15-_index)) @\
+ beq Ldone ## _index @\
+ lwz r0, 424+_index*16(r3) @\
+ stw r0, 0(r4) @\
+ lwz r0, 424+_index*16+4(r3) @\
+ stw r0, 4(r4) @\
+ lwz r0, 424+_index*16+8(r3) @\
+ stw r0, 8(r4) @\
+ lwz r0, 424+_index*16+12(r3)@\
+ stw r0, 12(r4) @\
+ lvx v ## _index,0,r4 @\
+Ldone ## _index:
+
+#define LOAD_VECTOR_UNALIGNEDh(_index) \
+ andi. r0,r5,(1<<(31-_index)) @\
+ beq Ldone ## _index @\
+ lwz r0, 424+_index*16(r3) @\
+ stw r0, 0(r4) @\
+ lwz r0, 424+_index*16+4(r3) @\
+ stw r0, 4(r4) @\
+ lwz r0, 424+_index*16+8(r3) @\
+ stw r0, 8(r4) @\
+ lwz r0, 424+_index*16+12(r3)@\
+ stw r0, 12(r4) @\
+ lvx v ## _index,0,r4 @\
+ Ldone ## _index:
+
+
+ LOAD_VECTOR_UNALIGNEDl(0)
+ LOAD_VECTOR_UNALIGNEDl(1)
+ LOAD_VECTOR_UNALIGNEDl(2)
+ LOAD_VECTOR_UNALIGNEDl(3)
+ LOAD_VECTOR_UNALIGNEDl(4)
+ LOAD_VECTOR_UNALIGNEDl(5)
+ LOAD_VECTOR_UNALIGNEDl(6)
+ LOAD_VECTOR_UNALIGNEDl(7)
+ LOAD_VECTOR_UNALIGNEDl(8)
+ LOAD_VECTOR_UNALIGNEDl(9)
+ LOAD_VECTOR_UNALIGNEDl(10)
+ LOAD_VECTOR_UNALIGNEDl(11)
+ LOAD_VECTOR_UNALIGNEDl(12)
+ LOAD_VECTOR_UNALIGNEDl(13)
+ LOAD_VECTOR_UNALIGNEDl(14)
+ LOAD_VECTOR_UNALIGNEDl(15)
+ LOAD_VECTOR_UNALIGNEDh(16)
+ LOAD_VECTOR_UNALIGNEDh(17)
+ LOAD_VECTOR_UNALIGNEDh(18)
+ LOAD_VECTOR_UNALIGNEDh(19)
+ LOAD_VECTOR_UNALIGNEDh(20)
+ LOAD_VECTOR_UNALIGNEDh(21)
+ LOAD_VECTOR_UNALIGNEDh(22)
+ LOAD_VECTOR_UNALIGNEDh(23)
+ LOAD_VECTOR_UNALIGNEDh(24)
+ LOAD_VECTOR_UNALIGNEDh(25)
+ LOAD_VECTOR_UNALIGNEDh(26)
+ LOAD_VECTOR_UNALIGNEDh(27)
+ LOAD_VECTOR_UNALIGNEDh(28)
+ LOAD_VECTOR_UNALIGNEDh(29)
+ LOAD_VECTOR_UNALIGNEDh(30)
+ LOAD_VECTOR_UNALIGNEDh(31)
+
+Lnovec:
+ lwz r0, 136(r3) ; __cr
+ mtocrf 255,r0
+ lwz r0, 148(r3) ; __ctr
+ mtctr r0
+ lwz r0, 0(r3) ; __ssr0
+ mtctr r0
+ lwz r0, 8(r3) ; do r0 now
+ lwz r5,28(r3) ; do r5 now
+ lwz r4,24(r3) ; do r4 now
+ lwz r1,12(r3) ; do sp now
+ lwz r3,20(r3) ; do r3 last
+ bctr
+
+
+#endif
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteDebuggerDummyUnwinder.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteDebuggerDummyUnwinder.hpp
new file mode 100644
index 00000000000..1db3faffd10
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteDebuggerDummyUnwinder.hpp
@@ -0,0 +1,88 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- RemoteDebuggerDummyUnwinder.hpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Code to unwind past a debugger's dummy frame inserted when it does an
+// inferior function call.
+// In this case we'll need to get the saved register context from the debugger -
+// it may be in the debugger's local memory or it may be saved in a nonstandard
+// location in the inferior process' memory.
+
+#ifndef __REMOTE_DEBUGGER_DUMMY_UNWINDER_HPP__
+#define __REMOTE_DEBUGGER_DUMMY_UNWINDER_HPP__
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#include "libunwind.h"
+#include "Registers.hpp"
+#include "AddressSpace.hpp"
+#include "RemoteRegisterMap.hpp"
+#include "RemoteProcInfo.hpp"
+
+namespace lldb_private
+{
+
+template <typename A>
+int stepOutOfDebuggerDummyFrame (A& addressSpace, Registers_x86_64& registers,
+ RemoteProcInfo *procinfo, uint64_t ip,
+ uint64_t sp, void* arg)
+{
+ Registers_x86_64 newRegisters(registers);
+ RemoteRegisterMap *rmap = addressSpace.getRemoteProcInfo()->getRegisterMap();
+ unw_word_t regv;
+ for (int i = UNW_X86_64_RAX; i <= UNW_X86_64_R15; i++) {
+ int driver_regnum;
+ if (!rmap->unwind_regno_to_caller_regno (i, driver_regnum))
+ continue;
+ if (addressSpace.accessors()->access_reg_inf_func_call (procinfo->wrap(), ip, sp, driver_regnum, &regv, 0, arg))
+ newRegisters.setRegister(i, regv);
+ }
+ if (!addressSpace.accessors()->access_reg_inf_func_call (procinfo->wrap(), ip, sp, rmap->caller_regno_for_ip(), &regv, 0, arg))
+ return UNW_EUNSPEC;
+ newRegisters.setIP (regv);
+ registers = newRegisters;
+ return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int stepOutOfDebuggerDummyFrame (A& addressSpace, Registers_x86& registers,
+ RemoteProcInfo *procinfo, uint64_t ip,
+ uint64_t sp, void* arg)
+{
+ Registers_x86 newRegisters(registers);
+ RemoteRegisterMap *rmap = addressSpace.getRemoteProcInfo()->getRegisterMap();
+ unw_word_t regv;
+ for (int i = UNW_X86_EAX; i <= UNW_X86_EDI; i++) {
+ int driver_regnum;
+ if (!rmap->unwind_regno_to_caller_regno (i, driver_regnum))
+ continue;
+ if (addressSpace.accessors()->access_reg_inf_func_call (procinfo->wrap(), ip, sp, driver_regnum, &regv, 0, arg))
+ newRegisters.setRegister(i, regv);
+ }
+ if (!addressSpace.accessors()->access_reg_inf_func_call (procinfo->wrap(), ip, sp, rmap->caller_regno_for_ip(), &regv, 0, arg))
+ return UNW_EUNSPEC;
+ newRegisters.setIP (regv);
+ registers = newRegisters;
+ return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int stepOutOfDebuggerDummyFrame (A& addressSpace, Registers_ppc& registers,
+ uint64_t ip, uint64_t sp)
+{
+ ABORT ("stepping out of a debugger dummy frame not supported on ppc");
+ return UNW_EUNSPEC;
+}
+
+}; // namespace lldb_private
+
+#endif // SUPPORT_REMOTE_UNWINDING
+
+#endif // __REMOTE_DEBUGGER_DUMMY_UNWINDER_HPP__
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteProcInfo.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteProcInfo.hpp
new file mode 100644
index 00000000000..3640dc6195c
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteProcInfo.hpp
@@ -0,0 +1,977 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- RemoteProcInfo.hpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This file defines the primary object created when unw_create_addr_space()
+// is called. This object tracks the list of known images in memory
+// (dylibs, bundles, etc), it maintains a link to a RemoteRegisterMap for this
+// architecture, it caches the remote process memory in a local store and all
+// read/writes are filtered through its accessors which will use the memory
+// caches. It maintains a logging level set by the driver program and puts
+// timing/debug messages out on a FILE* provided to it.
+
+// RemoteProcInfo is not specific to any particular unwind so it does not
+// maintain an "arg" argument (an opaque pointer that the driver program uses
+// to track the process/thread being unwound).
+
+#ifndef __REMOTE_PROC_INFO_HPP__
+#define __REMOTE_PROC_INFO_HPP__
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <stdarg.h>
+#include <sys/time.h>
+#include <mach-o/loader.h>
+#include <mach-o/getsect.h>
+#include <mach/ppc/thread_status.h>
+#include <mach/i386/thread_status.h>
+#include <Availability.h>
+
+#include <map>
+#include <vector>
+#include <algorithm>
+
+#include "FileAbstraction.hpp"
+#include "libunwind.h"
+#include "InternalMacros.h"
+#include "dwarf2.h"
+#include "RemoteUnwindProfile.h"
+#include "Registers.hpp"
+#include "RemoteRegisterMap.hpp"
+
+namespace lldb_private
+{
+class RemoteProcInfo;
+
+///
+/// unw_addr_space_remote is the concrete instance that a unw_addr_space_t points to when examining
+/// a remote process.
+///
+struct unw_addr_space_remote
+{
+ enum unw_as_type type; // should always be UNW_REMOTE
+ RemoteProcInfo* ras;
+};
+
+class RemoteMemoryBlob
+{
+public:
+ typedef void (*free_callback_with_arg)(void *, void*);
+ typedef void (*free_callback)(void *);
+
+ /* This object is constructed with a callback to free the memory;
+ that callback takes a pointer to the memory region and optionally
+ takes an additional argument -- the "void* arg" passed around for
+ remote unwinds, in case the driver program allocated this e.g. with
+ mach_vm_read, and needs the token to vm_deallocate it. */
+
+ RemoteMemoryBlob (uint8_t *buf, free_callback_with_arg to_free,
+ uint64_t startaddr, uint64_t len, uint64_t mh, void *arg) :
+ fBuf(buf), fToFreeWithArg(to_free), fToFree(NULL),
+ fStartAddr(startaddr), fLen(len), fMachHeader(mh),
+ fArg(arg) { }
+ RemoteMemoryBlob (uint8_t *buf, free_callback to_free, uint64_t startaddr,
+ uint64_t len, uint64_t mh, void *arg) :
+ fBuf(buf), fToFree(to_free), fToFreeWithArg(NULL),
+ fStartAddr(startaddr), fLen(len), fMachHeader(mh),
+ fArg(NULL) { }
+
+ // the following is to create a dummy RMB object for lower_bound's use in
+ // searching.
+ RemoteMemoryBlob (uint64_t startaddr) : fStartAddr(startaddr), fToFree(NULL),
+ fBuf(NULL), fToFreeWithArg(NULL), fArg(NULL), fMachHeader(-1),
+ fLen(0) { }
+ ~RemoteMemoryBlob () {
+ if (fToFreeWithArg)
+ fToFreeWithArg(fBuf, fArg);
+ else if (fToFree)
+ fToFree(fBuf);
+ }
+ bool contains_addr (uint64_t addr) {
+ if (fStartAddr <= addr && addr < fStartAddr + fLen)
+ return true;
+ else
+ return false;
+ }
+ uint8_t *get_blob_range (uint64_t remote_process_addr, int len) {
+ if (this->contains_addr (remote_process_addr) == false)
+ return NULL;
+ if (this->contains_addr (remote_process_addr + len) == false)
+ return NULL;
+ return fBuf + (remote_process_addr - fStartAddr);
+ }
+ uint64_t getMh () const { return fMachHeader; }
+ uint64_t getStartAddr() const { return fStartAddr; }
+ uint64_t getLength() const { return fLen; }
+private:
+ uint8_t *fBuf;
+ free_callback fToFree;
+ free_callback_with_arg fToFreeWithArg;
+ uint64_t fStartAddr;
+ uint64_t fLen;
+ uint64_t fMachHeader;
+ void *fArg;
+};
+
+inline bool operator<(const RemoteMemoryBlob &b1, const RemoteMemoryBlob &b2) {
+ if (b1.getStartAddr() < b2.getStartAddr())
+ return true;
+ else
+ return false;
+}
+
+// One of these for each image in memory (executable, dylib, bundle, etc)
+
+struct RemoteImageEntry
+{
+ RemoteImageEntry () : mach_header(0), text_start(0), text_end(0), eh_frame_start(0), eh_frame_len(0), compact_unwind_info_start(0), compact_unwind_info_len(0) { }
+ ~RemoteImageEntry () {
+ std::map<uint64_t, RemoteUnwindProfile *>::iterator i;
+ for (i = profiles.begin(); i != profiles.end(); ++i)
+ delete i->second;
+ }
+ uint64_t mach_header;
+ uint64_t text_start;
+ uint64_t text_end;
+ uint64_t eh_frame_start;
+ uint64_t eh_frame_len;
+ uint64_t compact_unwind_info_start;
+ uint64_t compact_unwind_info_len;
+
+ // unwind profiles created for thsi binary image so far,
+ // key is the start address of the profile.
+ std::map<uint64_t, RemoteUnwindProfile *> profiles;
+
+ // a list of function address bounds for this binary image -
+ // end addresses should be accurate and not inferred from potentially
+ // incomplete start-address data (e.g. nlist records).
+ std::vector<FuncBounds> func_bounds;
+};
+
+class RemoteImages
+{
+public:
+ RemoteImages (unw_targettype_t targarch) : fTargetArch(targarch) { }
+ ~RemoteImages ();
+ void removeAllImageProfiles();
+ void removeOneImageProfiles(uint64_t mh);
+ RemoteImageEntry *remoteEntryForTextAddr (uint64_t pc);
+ bool addFuncBounds (uint64_t mh, std::vector<FuncBounds> &startAddrs);
+ bool haveFuncBounds (uint64_t mh);
+ bool findFuncBounds (uint32_t pc, uint32_t &startAddr, uint32_t &endAddr);
+ bool findFuncBounds (uint64_t pc, uint64_t &startAddr, uint64_t &endAddr);
+ void addImage (uint64_t mh, uint64_t text_start, uint64_t text_end, uint64_t eh_frame, uint64_t eh_frame_len, uint64_t compact_unwind_start, uint64_t compact_unwind_len);
+ bool addProfile (RemoteProcInfo* procinfo, unw_accessors_t *acc, unw_addr_space_t as, uint64_t start, uint64_t end, void *arg);
+ RemoteUnwindProfile* findProfileByTextAddr (uint64_t pc);
+ void addMemBlob (RemoteMemoryBlob *blob);
+ uint8_t *getMemBlobMemory (uint64_t addr, int len);
+private:
+ RemoteImages();
+ std::map<uint64_t, RemoteImageEntry> fImages;
+ std::vector<RemoteMemoryBlob *> fMemBlobs;
+ unw_targettype_t fTargetArch;
+};
+
+RemoteImages::~RemoteImages () {
+ std::map<uint64_t, std::vector<RemoteMemoryBlob *> >::iterator i;
+ std::vector<RemoteMemoryBlob *>::iterator j;
+ for (j = fMemBlobs.begin(); j != fMemBlobs.end(); ++j) {
+ delete *j;
+ }
+ fMemBlobs.erase(fMemBlobs.begin(), fMemBlobs.end());
+}
+
+void RemoteImages::removeAllImageProfiles() {
+ fImages.erase(fImages.begin(), fImages.end());
+ std::vector<RemoteMemoryBlob *>::iterator j;
+ for (j = fMemBlobs.begin(); j != fMemBlobs.end(); ++j)
+ delete *j;
+ fMemBlobs.erase(fMemBlobs.begin(), fMemBlobs.end());
+}
+
+void RemoteImages::removeOneImageProfiles(uint64_t mh) {
+ std::map<uint64_t, RemoteImageEntry>::iterator i;
+ i = fImages.find(mh);
+ if (i != fImages.end())
+ fImages.erase(i);
+
+ std::vector<RemoteMemoryBlob *>::iterator j;
+ for (j = fMemBlobs.begin(); j != fMemBlobs.end(); ++j) {
+ if ((*j)->getMh() == mh) {
+ delete *j;
+ break;
+ }
+ }
+ if (j != fMemBlobs.end())
+ fMemBlobs.erase(j);
+}
+
+RemoteImageEntry *RemoteImages::remoteEntryForTextAddr (uint64_t pc) {
+ std::map<uint64_t, RemoteImageEntry>::iterator i = fImages.lower_bound (pc);
+ if (i == fImages.begin() && i == fImages.end())
+ return NULL;
+ if (i == fImages.end()) {
+ --i;
+ } else {
+ if (i != fImages.begin() && i->first != pc)
+ --i;
+ }
+ if (i->second.text_start <= pc && i->second.text_end > pc)
+ {
+ return &(i->second);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+bool RemoteImages::addFuncBounds (uint64_t mh, std::vector<FuncBounds> &startAddrs) {
+ RemoteImageEntry *img = NULL;
+ std::map<uint64_t, RemoteImageEntry>::iterator i = fImages.find (mh);
+ if (i == fImages.end())
+ return false;
+ img = &i->second;
+ img->func_bounds = startAddrs;
+ std::sort(img->func_bounds.begin(), img->func_bounds.end());
+ return true;
+}
+
+bool RemoteImages::haveFuncBounds (uint64_t mh) {
+ RemoteImageEntry *img = NULL;
+ std::map<uint64_t, RemoteImageEntry>::iterator i = fImages.find (mh);
+ if (i == fImages.end())
+ return false;
+ img = &i->second;
+ if (img->func_bounds.size() > 0)
+ return true;
+ return false;
+}
+
+bool RemoteImages::findFuncBounds (uint64_t pc, uint64_t &startAddr, uint64_t &endAddr) {
+ RemoteImageEntry *img = NULL;
+ startAddr = endAddr = 0;
+ std::map<uint64_t, RemoteImageEntry>::iterator i = fImages.lower_bound (pc);
+ if (i == fImages.begin() && i == fImages.end())
+ return false;
+ if (i == fImages.end()) {
+ --i;
+ } else {
+ if (i != fImages.begin() && i->first != pc)
+ --i;
+ }
+ if (i->second.text_start <= pc && i->second.text_end > pc)
+ {
+ img = &i->second;
+ }
+ else
+ return false;
+ std::vector<FuncBounds>::iterator j;
+ j = std::lower_bound(img->func_bounds.begin(), img->func_bounds.end(), FuncBounds (pc, pc));
+ if (j == img->func_bounds.begin() && j == img->func_bounds.end())
+ return false;
+ if (j == img->func_bounds.end()) {
+ --j;
+ } else {
+ if (j != img->func_bounds.begin() && j->fStart != pc)
+ --j;
+ }
+ if (j->fStart <= pc && j->fEnd > pc) {
+ startAddr = j->fStart;
+ endAddr = j->fEnd;
+ return true;
+ }
+ return false;
+}
+
+// Add 32-bit version of findFuncBounds so we can avoid templatizing all of these functions
+// just to handle 64 and 32 bit unwinds.
+
+bool RemoteImages::findFuncBounds (uint32_t pc, uint32_t &startAddr, uint32_t &endAddr) {
+ uint64_t big_startAddr = startAddr;
+ uint64_t big_endAddr = endAddr;
+ bool ret;
+ ret = findFuncBounds (pc, big_startAddr, big_endAddr);
+ startAddr = (uint32_t) big_startAddr & 0xffffffff;
+ endAddr = (uint32_t) big_endAddr & 0xffffffff;
+ return ret;
+}
+
+// Make sure we don't cache the same memory range more than once
+// I'm not checking the length of the blobs to check for overlap -
+// as this is used today, the only duplication will be with the same
+// start address.
+
+void RemoteImages::addMemBlob (RemoteMemoryBlob *blob) {
+ std::vector<RemoteMemoryBlob *>::iterator i;
+ for (i = fMemBlobs.begin(); i != fMemBlobs.end(); ++i) {
+ if (blob->getStartAddr() == (*i)->getStartAddr())
+ return;
+ }
+ fMemBlobs.push_back(blob);
+ std::sort(fMemBlobs.begin(), fMemBlobs.end());
+}
+
+uint8_t *RemoteImages::getMemBlobMemory (uint64_t addr, int len) {
+ uint8_t *res = NULL;
+ std::vector<RemoteMemoryBlob *>::iterator j;
+ RemoteMemoryBlob *searchobj = new RemoteMemoryBlob(addr);
+ j = std::lower_bound (fMemBlobs.begin(), fMemBlobs.end(), searchobj);
+ delete searchobj;
+ if (j == fMemBlobs.end() && j == fMemBlobs.begin())
+ return NULL;
+ if (j == fMemBlobs.end()) {
+ --j;
+ } else {
+ if (j != fMemBlobs.begin() && (*j)->getStartAddr() != addr)
+ --j;
+ }
+ res = (*j)->get_blob_range (addr, len);
+ if (res != NULL)
+ return res;
+ for (j = fMemBlobs.begin(); j != fMemBlobs.end(); ++j) {
+ res = (*j)->get_blob_range (addr, len);
+ if (res != NULL)
+ break;
+ }
+ return res;
+}
+
+void RemoteImages::addImage (uint64_t mh, uint64_t text_start,
+ uint64_t text_end, uint64_t eh_frame,
+ uint64_t eh_frame_len,
+ uint64_t compact_unwind_start,
+ uint64_t compact_unwind_len) {
+ struct RemoteImageEntry img;
+ img.mach_header = mh;
+ img.text_start = text_start;
+ img.text_end = text_end;
+ img.eh_frame_start = eh_frame;
+ img.eh_frame_len = eh_frame_len;
+ img.compact_unwind_info_start = compact_unwind_start;
+ img.compact_unwind_info_len = compact_unwind_len;
+ fImages[mh] = img;
+}
+
+// The binary image for this start/end address must already be present
+bool RemoteImages::addProfile (RemoteProcInfo* procinfo, unw_accessors_t *acc, unw_addr_space_t as, uint64_t start, uint64_t end, void *arg) {
+ RemoteImageEntry *img = NULL;
+ std::map<uint64_t, RemoteImageEntry>::iterator i = fImages.lower_bound (start);
+ if (i == fImages.begin() && i == fImages.end())
+ return false;
+ if (i == fImages.end()) {
+ --i;
+ } else {
+ if (i != fImages.begin() && i->first != start) {
+ --i;
+ }
+ }
+ if (i->second.text_start <= start && i->second.text_end > start)
+ {
+ img = &i->second;
+ }
+ else
+ return false;
+ RemoteUnwindProfile* profile = new RemoteUnwindProfile;
+ if (AssemblyParse (procinfo, acc, as, start, end, *profile, arg)) {
+ img->profiles[start] = profile;
+ return true;
+ }
+ return false;
+}
+
+RemoteUnwindProfile* RemoteImages::findProfileByTextAddr (uint64_t pc) {
+ RemoteImageEntry *img = NULL;
+ std::map<uint64_t, RemoteImageEntry>::iterator i = fImages.lower_bound (pc);
+ if (i == fImages.begin() && i == fImages.end())
+ return NULL;
+ if (i == fImages.end()) {
+ --i;
+ } else {
+ if (i != fImages.begin() && i->first != pc)
+ --i;
+ }
+ if (i->second.text_start <= pc && i->second.text_end > pc)
+ {
+ img = &i->second;
+ }
+ else
+ return false;
+ std::map<uint64_t, RemoteUnwindProfile *>::iterator j;
+ j = img->profiles.lower_bound (pc);
+ if (j == img->profiles.begin() && j == img->profiles.end())
+ return NULL;
+ if (j == img->profiles.end()) {
+ --j;
+ } else {
+ if (j != img->profiles.begin() && j->first != pc)
+ --j;
+ }
+ if (j->second->fStart <= pc && j->second->fEnd > pc)
+ {
+ return j->second;
+ }
+ return NULL;
+}
+
+///
+/// RemoteProcInfo is used as a template parameter to UnwindCursor when
+/// unwinding a thread that has a custom set of accessors. It calls the
+/// custom accessors for all data.
+///
+class RemoteProcInfo
+{
+public:
+
+// libunwind documentation specifies that unw_create_addr_space defaults to
+// UNW_CACHE_NONE but that's going to work very poorly for us so we're
+// defaulting to UNW_CACHE_GLOBAL.
+
+ RemoteProcInfo(unw_accessors_t* accessors, unw_targettype_t targarch) :
+ fAccessors(*accessors), fCachingPolicy(UNW_CACHE_GLOBAL),
+ fTargetArch(targarch), fImages(targarch), fLogging(NULL),
+ fLogLevel(UNW_LOG_LEVEL_NONE)
+ {
+ fWrapper.type = UNW_REMOTE;
+ fWrapper.ras = this;
+ fRemoteRegisterMap = new RemoteRegisterMap(accessors, targarch);
+ if (fTargetArch == UNW_TARGET_X86_64 || fTargetArch == UNW_TARGET_I386
+ || fTargetArch == UNW_TARGET_ARM)
+ fLittleEndian = true;
+ else
+ fLittleEndian = false;
+ }
+
+ ~RemoteProcInfo () {
+ delete fRemoteRegisterMap;
+ }
+
+ bool haveProfile (uint64_t pc) {
+ if (fImages.findProfileByTextAddr (pc))
+ return true;
+ else
+ return false;
+ }
+
+ // returns NULL if profile does not yet exist.
+ RemoteUnwindProfile* findProfile (uint64_t pc) {
+ return fImages.findProfileByTextAddr (pc);
+ }
+
+ // returns NULL if the binary image is not yet added.
+ bool addProfile (unw_accessors_t *acc, unw_addr_space_t as, uint64_t start, uint64_t end, void *arg) {
+ if (fImages.addProfile (this, acc, as, start, end, arg))
+ return true;
+ else
+ return false;
+ }
+
+ bool haveImageEntry (uint64_t pc, void *arg);
+
+ bool getImageAddresses (uint64_t pc, uint64_t &mh, uint64_t &text_start, uint64_t &text_end,
+ uint64_t &eh_frame_start, uint64_t &eh_frame_len, uint64_t &compact_unwind_start,
+ void *arg);
+ bool getImageAddresses (uint64_t pc, uint32_t &mh, uint32_t &text_start, uint32_t &text_end,
+ uint32_t &eh_frame_start, uint32_t &eh_frame_len, uint32_t &compact_unwind_start,
+ void *arg);
+
+ bool addFuncBounds (uint64_t mh, std::vector<FuncBounds> &startAddrs) { return fImages.addFuncBounds (mh, startAddrs); }
+ bool haveFuncBounds (uint64_t mh) { return fImages.haveFuncBounds (mh); }
+ bool findStartAddr (uint64_t pc, uint32_t &startAddr, uint32_t &endAddr) { return fImages.findFuncBounds (pc, startAddr, endAddr); }
+ bool findStartAddr (uint64_t pc, uint64_t &startAddr, uint64_t &endAddr) { return fImages.findFuncBounds (pc, startAddr, endAddr); }
+ uint8_t *getMemBlobMemory (uint64_t addr, int len) { return fImages.getMemBlobMemory (addr, len); }
+
+
+ // Functions to pull memory from the target into the debugger.
+
+ int getBytes(uint64_t addr, uint64_t extent, uint8_t* buf, void* arg)
+ {
+ int err = readRaw(addr, extent, buf, arg);
+
+ if(err)
+ return 0;
+
+ return 1;
+ }
+
+#define DECLARE_INT_ACCESSOR(bits) \
+ uint##bits##_t get##bits(uint64_t addr, void* arg) \
+ { \
+ uint##bits##_t ret; \
+ int err = readRaw(addr, (unw_word_t)(bits / 8), (uint8_t*)&ret, arg); \
+ \
+ if(err) \
+ ABORT("Invalid memory access in the target"); \
+ \
+ return ret; \
+ }
+ DECLARE_INT_ACCESSOR(8)
+ DECLARE_INT_ACCESSOR(16)
+ DECLARE_INT_ACCESSOR(32)
+ DECLARE_INT_ACCESSOR(64)
+#undef DECLARE_INT_ACCESSOR
+
+// 'err' is set to 0 if there were no errors reading this
+// memory. Non-zero values indicate that the memory was not
+// read successfully. This method should be preferred over the
+// method above which asserts on failure.
+
+#define DECLARE_INT_ACCESSOR_ERR(bits) \
+ uint##bits##_t get##bits(uint64_t addr, int &err, void* arg) \
+ { \
+ uint##bits##_t ret; \
+ err = readRaw(addr, (unw_word_t)(bits / 8), (uint8_t*)&ret, arg); \
+ \
+ return ret; \
+ }
+ DECLARE_INT_ACCESSOR_ERR(8)
+ DECLARE_INT_ACCESSOR_ERR(16)
+ DECLARE_INT_ACCESSOR_ERR(32)
+ DECLARE_INT_ACCESSOR_ERR(64)
+#undef DECLARE_INT_ACCESSOR_ERR
+
+ double getDouble(uint64_t addr, void* arg)
+ {
+ double ret;
+ int err = readRaw(addr, (unw_word_t)(sizeof(ret) / 8), (uint8_t*)&ret, arg);
+ if(err)
+ ABORT("Invalid memory access in the target");
+ return ret;
+ }
+
+ v128 getVector(uint64_t addr, void* arg)
+ {
+ v128 ret;
+ int err = readRaw(addr, (unw_word_t)(sizeof(ret) / 8), (uint8_t*)&ret, arg);
+ if(err)
+ ABORT("Invalid memory access in the target");
+ return ret;
+ }
+
+ // Pull an unsigned LEB128 from the target into the debugger as a uint64_t.
+ uint64_t getULEB128(uint64_t& addr, uint64_t end, void* arg)
+ {
+ uint64_t lAddr = addr;
+ uint64_t ret = 0;
+ uint8_t shift = 0;
+ uint64_t byte;
+ do {
+ if(lAddr == end)
+ ABORT("Truncated LEB128 number in the target");
+
+ byte = (uint64_t)get8(lAddr, arg);
+ lAddr++;
+
+ if(((shift == 63) && (byte > 0x01)) || (shift > 63))
+ ABORT("LEB128 number is larger than is locally representible");
+
+ ret |= ((byte & 0x7f) << shift);
+ shift += 7;
+ } while((byte & 0x80) == 0x80);
+ addr = lAddr;
+ return ret;
+ }
+
+ // Pull an unsigned LEB128 from the target into the debugger as a uint64_t.
+ uint64_t getULEB128(uint32_t& addr, uint32_t end, void* arg)
+ {
+ uint32_t lAddr = addr;
+ uint64_t ret = 0;
+ uint8_t shift = 0;
+ uint64_t byte;
+ do {
+ if(lAddr == end)
+ ABORT("Truncated LEB128 number in the target");
+
+ byte = (uint64_t)get8(lAddr, arg);
+ lAddr++;
+
+ if(((shift == 63) && (byte > 0x01)) || (shift > 63))
+ ABORT("LEB128 number is larger than is locally representible");
+
+ ret |= ((byte & 0x7f) << shift);
+ shift += 7;
+ } while((byte & 0x80) == 0x80);
+ addr = lAddr;
+ return ret;
+ }
+
+
+ // Pull a signed LEB128 from the target into the debugger as a uint64_t.
+ int64_t getSLEB128(uint64_t& addr, uint64_t end, void* arg)
+ {
+ uint64_t lAddr = addr;
+ uint64_t ret = 0;
+ uint8_t shift = 0;
+ uint64_t byte;
+ do {
+ if(lAddr == end)
+ ABORT("Truncated LEB128 number in the target");
+ byte = (uint64_t)get8(lAddr, arg);
+ lAddr++;
+ if(((shift == 63) && (byte > 0x01)) || (shift > 63))
+ ABORT("LEB128 number is larger than is locally representible");
+ ret |= ((byte & 0x7f) << shift);
+ shift += 7;
+ } while((byte & 0x80) == 0x80);
+ // Sign-extend
+ if((shift < (sizeof(int64_t) * 8)) && (byte & 0x40))
+ ret |= -(1 << shift);
+ addr = lAddr;
+ return ret;
+ }
+
+ // Pull a signed LEB128 from the target into the debugger as a uint64_t.
+ int64_t getSLEB128(uint32_t& addr, uint32_t end, void* arg)
+ {
+ uint32_t lAddr = addr;
+ uint64_t ret = 0;
+ uint8_t shift = 0;
+ uint64_t byte;
+ do {
+ if(lAddr == end)
+ ABORT("Truncated LEB128 number in the target");
+ byte = (uint64_t)get8(lAddr, arg);
+ lAddr++;
+ if(((shift == 63) && (byte > 0x01)) || (shift > 63))
+ ABORT("LEB128 number is larger than is locally representible");
+ ret |= ((byte & 0x7f) << shift);
+ shift += 7;
+ } while((byte & 0x80) == 0x80);
+ // Sign-extend
+ if((shift < (sizeof(int64_t) * 8)) && (byte & 0x40))
+ ret |= -(1 << shift);
+ addr = lAddr;
+ return ret;
+ }
+
+
+ uint64_t getP (uint64_t addr, void *arg) {
+ switch (fTargetArch) {
+ case UNW_TARGET_X86_64:
+ return get64(addr, arg);
+ break;
+ case UNW_TARGET_I386:
+ return get32(addr, arg);
+ break;
+ }
+ ABORT("Unknown target architecture.");
+ return 0;
+ }
+
+ uint64_t getP (uint64_t addr, int& err, void *arg) {
+ switch (fTargetArch) {
+ case UNW_TARGET_X86_64:
+ return get64(addr, err, arg);
+ break;
+ case UNW_TARGET_I386:
+ return get32(addr, err, arg);
+ break;
+ }
+ ABORT("Unknown target architecture.");
+ return 0;
+ }
+
+ bool findFunctionName(uint64_t addr, char *buf, size_t bufLen, unw_word_t *offset, void* arg);
+ bool findFunctionBounds(uint64_t addr, uint64_t& low, uint64_t& high, void* arg);
+ int setCachingPolicy(unw_caching_policy_t policy);
+
+ void setLoggingLevel(FILE *f, unw_log_level_t level);
+ void logInfo(const char *fmt, ...);
+ void logAPI(const char *fmt, ...);
+ void logVerbose(const char *fmt, ...);
+ void logDebug(const char *fmt, ...);
+ struct timeval *timestamp_start ();
+ void timestamp_stop (struct timeval *tstart, const char *fmt, ...);
+
+ void flushAllCaches() { fImages.removeAllImageProfiles(); }
+ void flushCacheByMachHeader(uint64_t mh) { fImages.removeOneImageProfiles(mh); }
+ unw_targettype_t getTargetArch() { return fTargetArch; }
+ unw_accessors_t* getAccessors () { return &fAccessors; }
+ RemoteRegisterMap* getRegisterMap() { return fRemoteRegisterMap; }
+ unw_addr_space_t wrap () { return (unw_addr_space_t) &fWrapper; }
+ bool remoteIsLittleEndian () { return fLittleEndian; }
+ unw_log_level_t getDebugLoggingLevel() { return fLogLevel; }
+ void addMemBlob (RemoteMemoryBlob *blob) { fImages.addMemBlob(blob); }
+ unw_caching_policy_t getCachingPolicy() { return fCachingPolicy; }
+
+private:
+ int readRaw(uint64_t addr, uint64_t extent, uint8_t *valp, void* arg)
+ {
+ uint8_t *t = this->getMemBlobMemory (addr, extent);
+ if (t) {
+ memcpy (valp, t, extent);
+ return 0;
+ }
+ return fAccessors.access_raw((unw_addr_space_t)this, addr, extent, valp, 0, arg);
+ }
+
+ struct unw_addr_space_remote fWrapper;
+ unw_accessors_t fAccessors;
+ unw_caching_policy_t fCachingPolicy;
+ unw_targettype_t fTargetArch;
+ unw_addr_space_t fAddrSpace;
+ RemoteImages fImages;
+ RemoteRegisterMap *fRemoteRegisterMap;
+ FILE *fLogging;
+ unw_log_level_t fLogLevel;
+ bool fLittleEndian;
+};
+
+// Find an image containing the given pc, returns false if absent and
+// we can't add it via the accessors.
+bool RemoteProcInfo::haveImageEntry (uint64_t pc, void *arg) {
+ if (fImages.remoteEntryForTextAddr (pc) == NULL) {
+ unw_word_t mh, text_start, text_end, eh_frame, eh_frame_len, compact_unwind, compact_unwind_len;
+ if (fAccessors.find_image_info (wrap(), pc, &mh, &text_start,
+ &text_end, &eh_frame, &eh_frame_len, &compact_unwind, &compact_unwind_len, arg) == UNW_ESUCCESS) {
+ fImages.addImage (mh, text_start, text_end, eh_frame, eh_frame_len, compact_unwind, compact_unwind_len);
+ if (fCachingPolicy != UNW_CACHE_NONE) {
+ if (compact_unwind_len != 0) {
+ logVerbose ("Creating RemoteMemoryBlob of compact unwind info image at mh 0x%llx, %lld bytes", mh, (uint64_t) compact_unwind_len);
+ uint8_t *buf = (uint8_t*) malloc (compact_unwind_len);
+ if (this->getBytes (compact_unwind, compact_unwind_len, buf, arg)) {
+ RemoteMemoryBlob *b = new RemoteMemoryBlob(buf, free, compact_unwind, compact_unwind_len, mh, NULL);
+ fImages.addMemBlob (b);
+ }
+ } else if (eh_frame_len != 0) {
+ logVerbose ("Creating RemoteMemoryBlob of eh_frame for image at mh 0x%llx, %lld bytes", mh, (uint64_t) compact_unwind_len);
+ uint8_t *buf = (uint8_t*) malloc (eh_frame_len);
+ if (this->getBytes (eh_frame, eh_frame_len, buf, arg)) {
+ RemoteMemoryBlob *b = new RemoteMemoryBlob(buf, free, eh_frame, eh_frame_len, mh, NULL);
+ fImages.addMemBlob (b);
+ }
+ }
+ }
+ } else {
+ return false; /// find_image_info failed
+ }
+ } else {
+ return true;
+ }
+ return true;
+}
+
+bool RemoteProcInfo::getImageAddresses (uint64_t pc, uint64_t &mh, uint64_t &text_start, uint64_t &text_end,
+ uint64_t &eh_frame_start, uint64_t &eh_frame_len, uint64_t &compact_unwind_start,
+ void *arg) {
+ // Make sure we have this RemoteImageEntry already - fetch it now if needed.
+ if (haveImageEntry (pc, arg) == false) {
+ return false;
+ }
+ RemoteImageEntry *r = fImages.remoteEntryForTextAddr (pc);
+ if (r) {
+ mh = r->mach_header;
+ text_start = r->text_start;
+ text_end = r->text_end;
+ eh_frame_start = r->eh_frame_start;
+ eh_frame_len = r->eh_frame_len;
+ compact_unwind_start = r->compact_unwind_info_start;
+ return true;
+ }
+ return false;
+}
+
+
+bool RemoteProcInfo::findFunctionName(uint64_t addr, char *buf, size_t bufLen, unw_word_t *offset, void* arg)
+{
+ if(fAccessors.get_proc_name(wrap(), addr, buf, bufLen, offset, arg) == UNW_ESUCCESS)
+ return true;
+ else
+ return false;
+}
+
+bool RemoteProcInfo::findFunctionBounds(uint64_t addr, uint64_t& low, uint64_t& high, void* arg)
+{
+ if (fAccessors.get_proc_bounds(wrap(), addr, &low, &high, arg) == UNW_ESUCCESS
+ && high != 0)
+ return true;
+ else
+ return false;
+}
+
+int RemoteProcInfo::setCachingPolicy(unw_caching_policy_t policy)
+{
+ if(policy == UNW_CACHE_NONE && fCachingPolicy != UNW_CACHE_NONE)
+ {
+ flushAllCaches();
+ }
+
+ if(!(policy == UNW_CACHE_NONE || policy == UNW_CACHE_GLOBAL || policy == UNW_CACHE_PER_THREAD))
+ return UNW_EINVAL;
+
+ fCachingPolicy = policy;
+
+ return UNW_ESUCCESS;
+}
+
+void RemoteProcInfo::setLoggingLevel(FILE *f, unw_log_level_t level)
+{
+ fLogLevel = level;
+ fLogging = f;
+}
+
+void RemoteProcInfo::logInfo(const char *fmt, ...)
+{
+ if (fLogging == NULL || fLogLevel == UNW_LOG_LEVEL_NONE)
+ return;
+ if (fLogLevel & UNW_LOG_LEVEL_INFO) {
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (fLogging, fmt, ap);
+ fputs ("\n", fLogging);
+ va_end (ap);
+ }
+}
+
+void RemoteProcInfo::logAPI(const char *fmt, ...)
+{
+ if (fLogging == NULL || fLogLevel == UNW_LOG_LEVEL_NONE)
+ return;
+ if (fLogLevel & UNW_LOG_LEVEL_API) {
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (fLogging, fmt, ap);
+ fputs ("\n", fLogging);
+ va_end (ap);
+ }
+}
+
+void RemoteProcInfo::logVerbose(const char *fmt, ...)
+{
+ if (fLogging == NULL || fLogLevel == UNW_LOG_LEVEL_NONE)
+ return;
+ if (fLogLevel & UNW_LOG_LEVEL_VERBOSE) {
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (fLogging, fmt, ap);
+ fputs ("\n", fLogging);
+ va_end (ap);
+ }
+}
+
+void RemoteProcInfo::logDebug(const char *fmt, ...)
+{
+ if (fLogging == NULL || fLogLevel == UNW_LOG_LEVEL_NONE)
+ return;
+ if (fLogLevel & UNW_LOG_LEVEL_DEBUG) {
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (fLogging, fmt, ap);
+ fputs ("\n", fLogging);
+ va_end (ap);
+ }
+}
+
+struct timeval *RemoteProcInfo::timestamp_start ()
+{
+ if (fLogging == NULL || fLogLevel == UNW_LOG_LEVEL_NONE)
+ return NULL;
+ if (fLogLevel & UNW_LOG_LEVEL_TIMINGS) {
+ struct timeval *t = (struct timeval *) malloc (sizeof (struct timeval));
+ if (gettimeofday (t, NULL) != 0) {
+ free (t);
+ return NULL;
+ }
+ return t;
+ }
+ return NULL;
+}
+
+void RemoteProcInfo::timestamp_stop (struct timeval *tstart, const char *fmt, ...)
+{
+ if (fLogging == NULL || fLogLevel == UNW_LOG_LEVEL_NONE || tstart == NULL)
+ return;
+ if (fLogLevel & UNW_LOG_LEVEL_TIMINGS) {
+ struct timeval tend;
+ if (gettimeofday (&tend, NULL) != 0) {
+ free (tstart);
+ return;
+ }
+ struct timeval result;
+ timersub (&tend, tstart, &result);
+ va_list ap;
+ va_start (ap, fmt);
+ vprintf (fmt, ap);
+ printf (" duration %0.5fs\n", (double) ((result.tv_sec * 1000000) + result.tv_usec) / 1000000.0);
+ va_end (ap);
+ free (tstart);
+ }
+}
+
+
+// Initialize the register context at the start of a remote unwind.
+
+void getRemoteContext (RemoteProcInfo* procinfo, Registers_x86_64& r, void *arg) {
+ unw_accessors_t* accessors = procinfo->getAccessors();
+ unw_addr_space_t addrSpace = procinfo->wrap();
+ RemoteRegisterMap* regmap = procinfo->getRegisterMap();
+ uint64_t rv;
+
+ // now that we have a selected process/thread, ask about the valid registers.
+ regmap->scan_caller_regs (addrSpace, arg);
+
+#define FILLREG(reg) {int caller_reg; regmap->unwind_regno_to_caller_regno ((reg), caller_reg); accessors->access_reg (addrSpace, caller_reg, &rv, 0, arg); r.setRegister ((reg), rv);}
+ FILLREG (UNW_X86_64_RAX);
+ FILLREG (UNW_X86_64_RDX);
+ FILLREG (UNW_X86_64_RCX);
+ FILLREG (UNW_X86_64_RBX);
+ FILLREG (UNW_X86_64_RSI);
+ FILLREG (UNW_X86_64_RDI);
+ FILLREG (UNW_X86_64_RBP);
+ FILLREG (UNW_X86_64_RSP);
+ FILLREG (UNW_X86_64_R8);
+ FILLREG (UNW_X86_64_R9);
+ FILLREG (UNW_X86_64_R10);
+ FILLREG (UNW_X86_64_R11);
+ FILLREG (UNW_X86_64_R12);
+ FILLREG (UNW_X86_64_R13);
+ FILLREG (UNW_X86_64_R14);
+ FILLREG (UNW_X86_64_R15);
+ FILLREG (UNW_REG_IP);
+#undef FILLREG
+}
+
+void getRemoteContext (RemoteProcInfo* procinfo, Registers_x86& r, void *arg) {
+ unw_accessors_t* accessors = procinfo->getAccessors();
+ unw_addr_space_t addrSpace = procinfo->wrap();
+ RemoteRegisterMap* regmap = procinfo->getRegisterMap();
+ uint64_t rv;
+
+ // now that we have a selected process/thread, ask about the valid registers.
+ regmap->scan_caller_regs (addrSpace, arg);
+
+#define FILLREG(reg) {int caller_reg; regmap->unwind_regno_to_caller_regno ((reg), caller_reg); accessors->access_reg (addrSpace, caller_reg, &rv, 0, arg); r.setRegister ((reg), rv);}
+ FILLREG (UNW_X86_EAX);
+ FILLREG (UNW_X86_ECX);
+ FILLREG (UNW_X86_EDX);
+ FILLREG (UNW_X86_EBX);
+ FILLREG (UNW_X86_EBP);
+ FILLREG (UNW_X86_ESP);
+ FILLREG (UNW_X86_ESI);
+ FILLREG (UNW_X86_EDI);
+ FILLREG (UNW_REG_IP);
+#undef FILLREG
+}
+
+
+void getRemoteContext (RemoteProcInfo* procinfo, Registers_ppc& r, void *arg) {
+ ABORT("ppc get remote context not implemented.");
+}
+
+}; // namespace lldb_private
+
+
+
+#endif // SUPPORT_REMOTE_UNWINDING
+#endif // __REMOTE_PROC_INFO_HPP__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteRegisterMap.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteRegisterMap.hpp
new file mode 100644
index 00000000000..19caae9a3f4
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteRegisterMap.hpp
@@ -0,0 +1,405 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- RemoteRegisterMap.hpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Provide conversions between reigster names, the libunwind internal enums,
+// and the register numbers the program calling libunwind are using.
+
+#ifndef __REMOTE_REGISTER_MAP_HPP__
+#define __REMOTE_REGISTER_MAP_HPP__
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+
+#include "libunwind.h"
+#include <vector>
+
+namespace lldb_private
+{
+class RemoteRegisterMap {
+public:
+ RemoteRegisterMap (unw_accessors_t *accessors, unw_targettype_t target);
+ ~RemoteRegisterMap ();
+ void initialize_x86_64 ();
+ void initialize_i386 ();
+ bool name_to_caller_regno (const char *name, int& callerr);
+ bool name_to_unwind_regno (const char *name, int& unwindr);
+ bool unwind_regno_to_caller_regno (int unwindr, int& callerr);
+ bool nonvolatile_reg_p (int unwind_regno);
+ bool argument_regnum_p (int unwind_regno);
+ const char *ip_register_name();
+ const char *sp_register_name();
+ int caller_regno_for_ip ();
+ int caller_regno_for_sp ();
+ int unwind_regno_for_frame_pointer ();
+ int unwind_regno_for_stack_pointer ();
+ int wordsize () { return fWordSize; }
+ void scan_caller_regs (unw_addr_space_t as, void *arg);
+
+ bool unwind_regno_to_machine_regno (int unwindr, int& machiner);
+ bool machine_regno_to_unwind_regno (int machr, int& unwindr);
+ bool caller_regno_to_unwind_regno (int callerr, int& unwindr);
+ const char* unwind_regno_to_name (int unwindr);
+ int byte_size_for_regtype (unw_regtype_t type);
+
+private:
+
+ // A structure that collects everything we need to know about a
+ // given register in one place.
+ struct reg {
+ int unwind_regno; // What libunwind-remote uses internally
+ int caller_regno; // What the libunwind-remote driver program uses
+ int eh_frame_regno; // What the eh_frame section uses
+ int machine_regno; // What the actual bits/bytes are in instructions
+ char *name;
+ unw_regtype_t type;
+ reg () : unwind_regno(-1), machine_regno(-1), caller_regno(-1),
+ eh_frame_regno(-1), name(NULL), type(UNW_NOT_A_REG) { }
+ };
+
+ unw_accessors_t fAccessors;
+ unw_targettype_t fTarget;
+ std::vector<RemoteRegisterMap::reg> fRegMap;
+ int fWordSize;
+};
+
+void RemoteRegisterMap::initialize_x86_64 () {
+#define DEFREG(ureg, ehno, machno, regn) {RemoteRegisterMap::reg r; r.unwind_regno = ureg; r.name = regn; r.eh_frame_regno = ehno; r.machine_regno = machno; r.type = UNW_INTEGER_REG; fRegMap.push_back(r); }
+ DEFREG (UNW_X86_64_RAX, 0, 0, strdup ("rax"));
+ DEFREG (UNW_X86_64_RDX, 1, 2, strdup ("rdx"));
+ DEFREG (UNW_X86_64_RCX, 2, 1, strdup ("rcx"));
+ DEFREG (UNW_X86_64_RBX, 3, 3, strdup ("rbx"));
+ DEFREG (UNW_X86_64_RSI, 4, 6, strdup ("rsi"));
+ DEFREG (UNW_X86_64_RDI, 5, 7, strdup ("rdi"));
+ DEFREG (UNW_X86_64_RBP, 6, 5, strdup ("rbp"));
+ DEFREG (UNW_X86_64_RSP, 7, 4, strdup ("rsp"));
+ DEFREG (UNW_X86_64_R8, 8, 8, strdup ("r8"));
+ DEFREG (UNW_X86_64_R9, 9, 9, strdup ("r9"));
+ DEFREG (UNW_X86_64_R10, 10, 10, strdup ("r10"));
+ DEFREG (UNW_X86_64_R11, 11, 11, strdup ("r11"));
+ DEFREG (UNW_X86_64_R12, 12, 12, strdup ("r12"));
+ DEFREG (UNW_X86_64_R13, 13, 13, strdup ("r13"));
+ DEFREG (UNW_X86_64_R14, 14, 14, strdup ("r14"));
+ DEFREG (UNW_X86_64_R15, 15, 15, strdup ("r15"));
+#undef DEFREG
+ RemoteRegisterMap::reg r;
+ r.name = strdup ("rip");
+ r.type = UNW_INTEGER_REG;
+ r.eh_frame_regno = 16;
+ fRegMap.push_back(r);
+}
+
+void RemoteRegisterMap::initialize_i386 () {
+#define DEFREG(ureg, ehno, machno, regn) {RemoteRegisterMap::reg r; r.unwind_regno = ureg; r.name = regn; r.eh_frame_regno = ehno; r.machine_regno = machno; r.type = UNW_INTEGER_REG; fRegMap.push_back(r); }
+ DEFREG (UNW_X86_EAX, 0, 0, strdup ("eax"));
+ DEFREG (UNW_X86_ECX, 1, 1, strdup ("ecx"));
+ DEFREG (UNW_X86_EDX, 2, 2, strdup ("edx"));
+ DEFREG (UNW_X86_EBX, 3, 3, strdup ("ebx"));
+ // i386 EH frame info has the next two swapped,
+ // v. gcc/config/i386/darwin.h:DWARF2_FRAME_REG_OUT.
+ DEFREG (UNW_X86_EBP, 4, 5, strdup ("ebp"));
+ DEFREG (UNW_X86_ESP, 5, 4, strdup ("esp"));
+ DEFREG (UNW_X86_ESI, 6, 6, strdup ("esi"));
+ DEFREG (UNW_X86_EDI, 7, 7, strdup ("edi"));
+#undef DEFREG
+ RemoteRegisterMap::reg r;
+ r.name = strdup ("eip");
+ r.type = UNW_INTEGER_REG;
+ r.eh_frame_regno = 8;
+ fRegMap.push_back(r);
+}
+
+
+RemoteRegisterMap::RemoteRegisterMap (unw_accessors_t *accessors, unw_targettype_t target) {
+ fAccessors = *accessors;
+ fTarget = target;
+ switch (target) {
+ case UNW_TARGET_X86_64:
+ this->initialize_x86_64();
+ fWordSize = 8;
+ break;
+ case UNW_TARGET_I386:
+ this->initialize_i386();
+ fWordSize = 4;
+ break;
+ default:
+ ABORT("RemoteRegisterMap called with unknown target");
+ }
+}
+
+RemoteRegisterMap::~RemoteRegisterMap () {
+ std::vector<RemoteRegisterMap::reg>::iterator j;
+ for (j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ free (j->name);
+}
+
+bool RemoteRegisterMap::name_to_caller_regno (const char *name, int& callerr) {
+ if (name == NULL)
+ return false;
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (strcasecmp (j->name, name) == 0) {
+ callerr = j->caller_regno;
+ return true;
+ }
+ return false;
+}
+
+bool RemoteRegisterMap::unwind_regno_to_caller_regno (int unwindr, int& callerr) {
+ if (unwindr == UNW_REG_IP) {
+ callerr = this->caller_regno_for_ip ();
+ return true;
+ }
+ if (unwindr == UNW_REG_SP) {
+ callerr = this->caller_regno_for_sp ();
+ return true;
+ }
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (j->unwind_regno == unwindr && j->caller_regno != -1) {
+ callerr = j->caller_regno;
+ return true;
+ }
+ return false;
+}
+
+bool RemoteRegisterMap::nonvolatile_reg_p (int unwind_regno) {
+ if (fTarget == UNW_TARGET_X86_64) {
+ switch (unwind_regno) {
+ case UNW_X86_64_RBX:
+ case UNW_X86_64_RSP:
+ case UNW_X86_64_RBP: // not actually a nonvolatile but often treated as such by convention
+ case UNW_X86_64_R12:
+ case UNW_X86_64_R13:
+ case UNW_X86_64_R14:
+ case UNW_X86_64_R15:
+ case UNW_REG_IP:
+ case UNW_REG_SP:
+ return true;
+ break;
+ default:
+ return false;
+ }
+ }
+ if (fTarget == UNW_TARGET_I386) {
+ switch (unwind_regno) {
+ case UNW_X86_EBX:
+ case UNW_X86_EBP: // not actually a nonvolatile but often treated as such by convention
+ case UNW_X86_ESI:
+ case UNW_X86_EDI:
+ case UNW_X86_ESP:
+ case UNW_REG_IP:
+ case UNW_REG_SP:
+ return true;
+ break;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+
+bool RemoteRegisterMap::argument_regnum_p (int unwind_regno) {
+ if (fTarget == UNW_TARGET_X86_64) {
+ switch (unwind_regno) {
+ case UNW_X86_64_RDI: /* arg 1 */
+ case UNW_X86_64_RSI: /* arg 2 */
+ case UNW_X86_64_RDX: /* arg 3 */
+ case UNW_X86_64_RCX: /* arg 4 */
+ case UNW_X86_64_R8: /* arg 5 */
+ case UNW_X86_64_R9: /* arg 6 */
+ return true;
+ break;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+const char *RemoteRegisterMap::ip_register_name () {
+ switch (fTarget) {
+ case UNW_TARGET_X86_64:
+ return "rip";
+ case UNW_TARGET_I386:
+ return "eip";
+ default:
+ ABORT("unsupported architecture");
+ }
+ return NULL;
+}
+
+const char *RemoteRegisterMap::sp_register_name () {
+ switch (fTarget) {
+ case UNW_TARGET_X86_64:
+ return "rsp";
+ case UNW_TARGET_I386:
+ return "esp";
+ default:
+ ABORT("unsupported architecture");
+ }
+ return NULL;
+}
+
+int RemoteRegisterMap::caller_regno_for_ip () {
+ int callerr;
+ if (this->name_to_caller_regno (this->ip_register_name(), callerr))
+ return callerr;
+ return -1;
+}
+
+int RemoteRegisterMap::caller_regno_for_sp () {
+ int callerr;
+ if (this->name_to_caller_regno (this->sp_register_name(), callerr))
+ return callerr;
+ return -1;
+}
+
+int RemoteRegisterMap::unwind_regno_for_frame_pointer () {
+ switch (fTarget) {
+ case UNW_TARGET_X86_64:
+ return UNW_X86_64_RBP;
+ case UNW_TARGET_I386:
+ return UNW_X86_EBP;
+ default:
+ ABORT("cannot be reached");
+ }
+ return -1;
+}
+
+int RemoteRegisterMap::unwind_regno_for_stack_pointer () {
+ switch (fTarget) {
+ case UNW_TARGET_X86_64:
+ return UNW_X86_64_RSP;
+ case UNW_TARGET_I386:
+ return UNW_X86_ESP;
+ default:
+ ABORT("cannot be reached");
+ }
+ return -1;
+}
+
+// This call requires a "arg" which specifies a given process/thread to
+// complete unlike the rest of the RegisterMap functions. Ideally this
+// would be in the ctor but the register map is created when an
+// AddressSpace is created and we don't have a process/thread yet.
+
+void RemoteRegisterMap::scan_caller_regs (unw_addr_space_t as, void *arg) {
+ for (int i = 0; i < 256; i++) {
+ unw_regtype_t type;
+ char namebuf[16];
+ if (fAccessors.reg_info (as, i, &type, namebuf, sizeof (namebuf), arg) == UNW_ESUCCESS
+ && type != UNW_NOT_A_REG) {
+ std::vector<RemoteRegisterMap::reg>::iterator j;
+ for (j = fRegMap.begin(); j != fRegMap.end(); ++j) {
+ if (strcasecmp (j->name, namebuf) == 0) {
+ j->caller_regno = i;
+ // if we haven't picked up a reg type yet it will be UNW_NOT_A_REG via the ctor
+ if (j->type == UNW_NOT_A_REG)
+ j->type = type;
+ if (j->type != type) {
+ ABORT("Caller and libunwind disagree about type of register");
+ break;
+ }
+ }
+ }
+ // caller knows about a register we don't have a libunwind entry for
+ if (j == fRegMap.end()) {
+ RemoteRegisterMap::reg r;
+ r.name = strdup (namebuf);
+ r.caller_regno = i;
+ r.type = type;
+ fRegMap.push_back(r);
+ }
+ }
+ }
+}
+
+
+bool RemoteRegisterMap::name_to_unwind_regno (const char *name, int& unwindr) {
+ if (name == NULL)
+ return false;
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (strcasecmp (j->name, name) == 0) {
+ unwindr = j->unwind_regno;
+ return true;
+ }
+ return false;
+}
+
+bool RemoteRegisterMap::unwind_regno_to_machine_regno (int unwindr, int& machiner) {
+ if (unwindr == UNW_REG_IP)
+ unwindr = this->caller_regno_for_ip ();
+ if (unwindr == UNW_REG_SP)
+ unwindr = this->caller_regno_for_sp ();
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (j->unwind_regno == unwindr && j->machine_regno != -1) {
+ machiner = j->machine_regno;
+ return true;
+ }
+ return false;
+}
+bool RemoteRegisterMap::machine_regno_to_unwind_regno (int machr, int& unwindr) {
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (j->machine_regno == machr && j->unwind_regno != -1) {
+ unwindr = j->unwind_regno;
+ return true;
+ }
+ return false;
+}
+bool RemoteRegisterMap::caller_regno_to_unwind_regno (int callerr, int& unwindr) {
+ if (this->caller_regno_for_ip() == callerr) {
+ unwindr = UNW_REG_IP;
+ return true;
+ }
+ if (this->caller_regno_for_sp() == callerr) {
+ unwindr = UNW_REG_SP;
+ return true;
+ }
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (j->caller_regno == callerr && j->unwind_regno != -1) {
+ unwindr = j->unwind_regno;
+ return true;
+ }
+ return false;
+}
+
+const char* RemoteRegisterMap::unwind_regno_to_name (int unwindr) {
+ for (std::vector<RemoteRegisterMap::reg>::iterator j = fRegMap.begin(); j != fRegMap.end(); ++j)
+ if (j->unwind_regno == unwindr && j->name != NULL) {
+ return j->name;
+ }
+ return NULL;
+}
+
+int RemoteRegisterMap::byte_size_for_regtype (unw_regtype_t type) {
+ switch (type) {
+ case UNW_TARGET_X86_64:
+ case UNW_TARGET_I386:
+ if (type == UNW_INTEGER_REG) return fWordSize;
+ if (type == UNW_FLOATING_POINT_REG) return 8;
+ if (type == UNW_VECTOR_REG) return 16;
+ default:
+ ABORT("cannot be reached");
+ }
+ return -1;
+}
+
+
+}; // namespace lldb_private
+
+#endif // SUPPORT_REMOTE_UNWINDING
+
+#endif // __REMOTE_REGISTER_MAP_HPP__
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteUnwindProfile.h b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteUnwindProfile.h
new file mode 100644
index 00000000000..b03551cd21c
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/RemoteUnwindProfile.h
@@ -0,0 +1,85 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- RemoteUnwindProfile.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWIND_PROFILE_H__
+#define __UNWIND_PROFILE_H__
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#include <vector>
+
+// The architecture-independent profile of a function's prologue
+
+namespace lldb_private
+{
+
+class RemoteUnwindProfile {
+public:
+ RemoteUnwindProfile () : fRegistersSaved(32, 0), fRegSizes(10, 0) { }
+ struct CFALocation {
+ int regno;
+ int offset;
+ };
+ enum RegisterSavedWhere { kRegisterOffsetFromCFA, kRegisterIsCFA };
+ enum RegisterType { kGeneralPurposeRegister = 0, kFloatingPointRegister, kVectorRegister };
+ struct SavedReg {
+ int regno;
+ RegisterSavedWhere location;
+ int64_t value;
+ int adj; // Used in kRegisterInRegister e.g. when we recover the caller's rsp by
+ // taking the contents of rbp and subtracting 16.
+ RegisterType type;
+ };
+ // In the following maps the key is the address after which this change has effect.
+ //
+ // 0 push %rbp
+ // 1 mov %rsp, %rbp
+ // 2 sub $16, %rsp
+ //
+ // At saved_registers<2> we'll find the record stating that rsp is now stored in rbp.
+
+ std::map<uint64_t, CFALocation> cfa;
+ std::map<uint64_t, std::vector<SavedReg> > saved_registers;
+
+ struct CFALocation initial_cfa; // At entry to the function
+
+ std::vector<uint8_t> fRegistersSaved;
+ std::vector<uint8_t> fRegSizes;
+ SavedReg returnAddress;
+ uint64_t fStart, fEnd; // low and high pc values for this function.
+ // END is the addr of the first insn outside the function.
+ uint64_t fFirstInsnPastPrologue;
+};
+
+class RemoteProcInfo;
+
+bool AssemblyParse (RemoteProcInfo *procinfo, unw_accessors_t *as, unw_addr_space_t as, uint64_t start, uint64_t end, RemoteUnwindProfile &profile, void *arg);
+
+
+class FuncBounds {
+ public:
+ FuncBounds (uint64_t low, uint64_t high) : fStart(low), fEnd(high) { }
+ uint64_t fStart;
+ uint64_t fEnd;
+};
+
+inline bool operator<(const FuncBounds &ap1, const FuncBounds &ap2) {
+ if (ap1.fStart < ap2.fStart)
+ return true;
+ if (ap1.fStart == ap2.fStart && ap1.fEnd < ap2.fEnd)
+ return true;
+ return false;
+}
+
+
+};
+#endif
+
+
+#endif // __UNWIND_PROFILE_H__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/Unwind-sjlj.c b/lldb/source/Plugins/Process/Utility/libunwind/src/Unwind-sjlj.c
new file mode 100644
index 00000000000..584528353a4
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/Unwind-sjlj.c
@@ -0,0 +1,466 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- Unwind-sjlj.c -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/*
+ *
+ * Implements setjump-longjump based C++ exceptions
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <setjmp.h>
+
+#include "unwind.h"
+#include "InternalMacros.h"
+
+//
+// ARM uses setjump/longjump based C++ exceptions.
+// Other architectures use "zero cost" exceptions.
+//
+// With SJLJ based exceptions any function that has a catch clause or needs to do any clean up when
+// an exception propagates through it, needs to call _Unwind_SjLj_Register() at the start of the
+// function and _Unwind_SjLj_Unregister() at the end. The register function is called with the
+// address of a block of memory in the function's stack frame. The runtime keeps a linked list
+// (stack) of these blocks - one per thread. The calling function also sets the personality
+// and lsda fields of the block.
+//
+//
+#if __arm__
+
+struct _Unwind_FunctionContext
+{
+ // next function in stack of handlers
+ struct _Unwind_FunctionContext* prev;
+
+ // set by calling function before registering to be the landing pad
+ uintptr_t resumeLocation;
+
+ // set by personality handler to be parameters passed to landing pad function
+ uintptr_t resumeParameters[4];
+
+ // set by calling function before registering
+ __personality_routine personality; // arm offset=24
+ uintptr_t lsda; // arm offset=28
+
+ // variable length array, contains registers to restore
+ // 0 = r7, 1 = pc, 2 = sp
+ void* jbuf[];
+};
+
+
+#if FOR_DYLD
+ // implemented in dyld
+ extern struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack();
+ extern void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc);
+#else
+ static pthread_key_t sPerThreadTopOfFunctionStack = 0;
+ static pthread_once_t sOnceFlag = PTHREAD_ONCE_INIT;
+
+ static void __Unwind_SjLj_MakeTopOfFunctionStackKey()
+ {
+ pthread_key_create(&sPerThreadTopOfFunctionStack, NULL);
+ }
+
+ static struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack()
+ {
+ pthread_once(&sOnceFlag, __Unwind_SjLj_MakeTopOfFunctionStackKey);
+ return (struct _Unwind_FunctionContext*)pthread_getspecific(sPerThreadTopOfFunctionStack);
+ }
+
+ static void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc)
+ {
+ pthread_once(&sOnceFlag, __Unwind_SjLj_MakeTopOfFunctionStackKey);
+ pthread_setspecific(sPerThreadTopOfFunctionStack, fc);
+ }
+#endif
+
+
+//
+// Called at start of each function that catches exceptions
+//
+EXPORT void _Unwind_SjLj_Register(struct _Unwind_FunctionContext* fc)
+{
+ fc->prev = __Unwind_SjLj_GetTopOfFunctionStack();
+ __Unwind_SjLj_SetTopOfFunctionStack(fc);
+}
+
+
+//
+// Called at end of each function that catches exceptions
+//
+EXPORT void _Unwind_SjLj_Unregister(struct _Unwind_FunctionContext* fc)
+{
+ __Unwind_SjLj_SetTopOfFunctionStack(fc->prev);
+}
+
+
+static _Unwind_Reason_Code unwind_phase1(struct _Unwind_Exception* exception_object)
+{
+ _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+ DEBUG_PRINT_UNWINDING("unwind_phase1: initial function-context=%p\n", c);
+
+ // walk each frame looking for a place to stop
+ for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {
+
+ // check for no more frames
+ if ( c == NULL ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): reached bottom => _URC_END_OF_STACK\n", exception_object);
+ return _URC_END_OF_STACK;
+ }
+
+ DEBUG_PRINT_UNWINDING("unwind_phase1: function-context=%p\n", c);
+ // if there is a personality routine, ask it if it will want to stop at this frame
+ if ( c->personality != NULL ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): calling personality function %p\n", exception_object, c->personality);
+ _Unwind_Reason_Code personalityResult = (*c->personality)(1, _UA_SEARCH_PHASE,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)c);
+ switch ( personalityResult ) {
+ case _URC_HANDLER_FOUND:
+ // found a catch clause or locals that need destructing in this frame
+ // stop search and remember function context
+ handlerNotFound = false;
+ exception_object->private_2 = (uintptr_t)c;
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND\n", exception_object);
+ return _URC_NO_REASON;
+
+ case _URC_CONTINUE_UNWIND:
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
+ // continue unwinding
+ break;
+
+ default:
+ // something went wrong
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+ }
+ }
+ return _URC_NO_REASON;
+}
+
+
+static _Unwind_Reason_Code unwind_phase2(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
+
+ // walk each frame until we reach where search phase said to stop
+ _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+ while ( true ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2s(ex_ojb=%p): function-context=%p\n", exception_object, c);
+
+ // check for no more frames
+ if ( c == NULL ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
+ return _URC_END_OF_STACK;
+ }
+
+ // if there is a personality routine, tell it we are unwinding
+ if ( c->personality != NULL ) {
+ _Unwind_Action action = _UA_CLEANUP_PHASE;
+ if ( (uintptr_t)c == exception_object->private_2 )
+ action = (_Unwind_Action)(_UA_CLEANUP_PHASE|_UA_HANDLER_FRAME); // tell personality this was the frame it marked in phase 1
+ _Unwind_Reason_Code personalityResult = (*c->personality)(1, action,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)c);
+ switch ( personalityResult ) {
+ case _URC_CONTINUE_UNWIND:
+ // continue unwinding
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
+ if ( (uintptr_t)c == exception_object->private_2 ) {
+ // phase 1 said we would stop at this frame, but we did not...
+ ABORT("during phase1 personality function said it would stop here, but now if phase2 it did not stop here");
+ }
+ break;
+ case _URC_INSTALL_CONTEXT:
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT, will resume at landing pad %p\n", exception_object, c->jbuf[1]);
+ // personality routine says to transfer control to landing pad
+ // we may get control back if landing pad calls _Unwind_Resume()
+ __Unwind_SjLj_SetTopOfFunctionStack(c);
+ __builtin_longjmp(c->jbuf, 1);
+ // unw_resume() only returns if there was an error
+ return _URC_FATAL_PHASE2_ERROR;
+ default:
+ // something went wrong
+ DEBUG_MESSAGE("personality function returned unknown result %d", personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ c = c->prev;
+ }
+
+ // clean up phase did not resume at the frame that the search phase said it would
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+static _Unwind_Reason_Code unwind_phase2_forced(struct _Unwind_Exception* exception_object,
+ _Unwind_Stop_Fn stop, void* stop_parameter)
+{
+ // walk each frame until we reach where search phase said to stop
+ _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+ while ( true ) {
+
+ // get next frame (skip over first which is _Unwind_RaiseException)
+ if ( c == NULL ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
+ return _URC_END_OF_STACK;
+ }
+
+ // call stop function at each frame
+ _Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE);
+ _Unwind_Reason_Code stopResult = (*stop)(1, action,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)c, stop_parameter);
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", exception_object, stopResult);
+ if ( stopResult != _URC_NO_REASON ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // if there is a personality routine, tell it we are unwinding
+ if ( c->personality != NULL ) {
+ __personality_routine p = (__personality_routine)c->personality;
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", exception_object, p);
+ _Unwind_Reason_Code personalityResult = (*p)(1, action,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)c);
+ switch ( personalityResult ) {
+ case _URC_CONTINUE_UNWIND:
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_CONTINUE_UNWIND\n", exception_object);
+ // destructors called, continue unwinding
+ break;
+ case _URC_INSTALL_CONTEXT:
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_INSTALL_CONTEXT\n", exception_object);
+ // we may get control back if landing pad calls _Unwind_Resume()
+ __Unwind_SjLj_SetTopOfFunctionStack(c);
+ __builtin_longjmp(c->jbuf, 1);
+ break;
+ default:
+ // something went wrong
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned %d, _URC_FATAL_PHASE2_ERROR\n",
+ exception_object, personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ c = c->prev;
+ }
+
+ // call stop function one last time and tell it we've reached the end of the stack
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop function with _UA_END_OF_STACK\n", exception_object);
+ _Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE|_UA_END_OF_STACK);
+ (*stop)(1, lastAction, exception_object->exception_class, exception_object, (struct _Unwind_Context*)c, stop_parameter);
+
+ // clean up phase did not resume at the frame that the search phase said it would
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+//
+// Called by __cxa_throw. Only returns if there is a fatal error
+//
+EXPORT _Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_SjLj_RaiseException(ex_obj=%p)\n", exception_object);
+
+ // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right thing
+ exception_object->private_1 = 0;
+ exception_object->private_2 = 0;
+
+ // phase 1: the search phase
+ _Unwind_Reason_Code phase1 = unwind_phase1(exception_object);
+ if ( phase1 != _URC_NO_REASON )
+ return phase1;
+
+ // phase 2: the clean up phase
+ return unwind_phase2(exception_object);
+}
+
+
+//
+// When _Unwind_RaiseException() is in phase2, it hands control
+// to the personality function at each frame. The personality
+// may force a jump to a landing pad in that function, the landing
+// pad code may then call _Unwind_Resume() to continue with the
+// unwinding. Note: the call to _Unwind_Resume() is from compiler
+// geneated user code. All other _Unwind_* routines are called
+// by the C++ runtime __cxa_* routines.
+//
+// Re-throwing an exception is implemented by having the code call
+// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
+//
+EXPORT void _Unwind_SjLj_Resume(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_SjLj_Resume(ex_obj=%p)\n", exception_object);
+
+ if ( exception_object->private_1 != 0 )
+ unwind_phase2_forced(exception_object, (_Unwind_Stop_Fn)exception_object->private_1, (void*)exception_object->private_2);
+ else
+ unwind_phase2(exception_object);
+
+ // clients assume _Unwind_Resume() does not return, so all we can do is abort.
+ ABORT("_Unwind_SjLj_Resume() can't return");
+}
+
+
+//
+// Called by __cxa_rethrow()
+//
+EXPORT _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n", exception_object, exception_object->private_1);
+ // if this is non-forced and a stopping place was found, then this is a re-throw
+ // call _Unwind_RaiseException() as if this was a new exception
+ if ( exception_object->private_1 == 0 )
+ _Unwind_SjLj_RaiseException(exception_object);
+
+ // call through to _Unwind_Resume() which distiguishes between forced and regular exceptions
+ _Unwind_SjLj_Resume(exception_object);
+ ABORT("__Unwind_SjLj_Resume_or_Rethrow() called _Unwind_SjLj_Resume() which unexpectedly returned");
+}
+
+
+//
+// Called by personality handler during phase 2 to get LSDA for current frame
+//
+EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context)
+{
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%0lX\n", context, ufc->lsda);
+ return ufc->lsda;
+}
+
+
+//
+// Called by personality handler during phase 2 to get register values
+//
+EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index)
+{
+ DEBUG_PRINT_API("_Unwind_GetGR(context=%p, reg=%d)\n", context, index);
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ return ufc->resumeParameters[index];
+}
+
+
+
+//
+// Called by personality handler during phase 2 to alter register values
+//
+EXPORT void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value)
+{
+ DEBUG_PRINT_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0lX)\n", context, index, new_value);
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ ufc->resumeParameters[index] = new_value;
+}
+
+
+//
+// Called by personality handler during phase 2 to get instruction pointer
+//
+EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context* context)
+{
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ DEBUG_PRINT_API("_Unwind_GetIP(context=%p) => 0x%lX\n", context, ufc->resumeLocation+1);
+ return ufc->resumeLocation+1;
+}
+
+//
+// Called by personality handler during phase 2 to get instruction pointer
+// ipBefore is a boolean that says if IP is already adjusted to be the call
+// site address. Normally IP is the return address.
+//
+EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore)
+{
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ *ipBefore = 0;
+ DEBUG_PRINT_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX\n", context, ipBefore, ufc->resumeLocation+1);
+ return ufc->resumeLocation+1;
+}
+
+
+//
+// Called by personality handler during phase 2 to alter instruction pointer
+//
+EXPORT void _Unwind_SetIP(struct _Unwind_Context* context, uintptr_t new_value)
+{
+ DEBUG_PRINT_API("_Unwind_SetIP(context=%p, value=0x%0lX)\n", context, new_value);
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ ufc->resumeLocation = new_value-1;
+}
+
+//
+// Called by personality handler during phase 2 to find the start of the function
+//
+EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context)
+{
+ // Not supported or needed for sjlj based unwinding
+ DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p)\n", context);
+ return 0;
+}
+
+//
+// Called by personality handler during phase 2 if a foreign exception is caught
+//
+EXPORT void _Unwind_DeleteException(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_DeleteException(ex_obj=%p)\n", exception_object);
+ if ( exception_object->exception_cleanup != NULL )
+ (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object);
+}
+
+
+//
+// Called by personality handler during phase 2 to get base address for data relative encodings
+//
+EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context)
+{
+ // Not supported or needed for sjlj based unwinding
+ DEBUG_PRINT_API("_Unwind_GetDataRelBase(context=%p)\n", context);
+ ABORT("_Unwind_GetDataRelBase() not implemented");
+}
+
+
+//
+// Called by personality handler during phase 2 to get base address for text relative encodings
+//
+EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context)
+{
+ // Not supported or needed for sjlj based unwinding
+ DEBUG_PRINT_API("_Unwind_GetTextRelBase(context=%p)\n", context);
+ ABORT("_Unwind_GetTextRelBase() not implemented");
+}
+
+
+
+//
+// Called by personality handler to get Call Frame Area for current frame
+//
+EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context* context)
+{
+ DEBUG_PRINT_API("_Unwind_GetCFA(context=%p)\n", context);
+ if ( context != NULL ) {
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
+ // setjmp/longjmp based exceptions don't have a true CFA
+ // the SP in the jmpbuf is the closest approximation
+ return (uintptr_t)ufc->jbuf[2];
+ }
+ return 0;
+}
+
+
+
+
+
+#endif // __arm__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp
new file mode 100644
index 00000000000..e940b8b8bf1
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindCursor.hpp
@@ -0,0 +1,1307 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- UnwindCursor.hpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//
+// C++ interface to lower levels of libuwind
+//
+
+#ifndef __UNWINDCURSOR_HPP__
+#define __UNWINDCURSOR_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <stdarg.h>
+
+#include "libunwind.h"
+
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "DwarfInstructions.hpp"
+
+#include "AssemblyParser.hpp"
+#include "AssemblyInstructions.hpp"
+#include "RemoteProcInfo.hpp"
+#include "ArchDefaultUnwinder.hpp"
+#include "RemoteDebuggerDummyUnwinder.hpp"
+
+#include "CompactUnwinder.hpp"
+#include "InternalMacros.h"
+
+// private keymgr stuff
+#define KEYMGR_GCC3_DW2_OBJ_LIST 302
+extern "C" {
+ extern void _keymgr_set_and_unlock_processwide_ptr(int key, void* ptr);
+ extern void* _keymgr_get_and_lock_processwide_ptr(int key);
+};
+
+// undocumented libgcc "struct object"
+struct libgcc_object
+{
+ void* start;
+ void* unused1;
+ void* unused2;
+ void* fde;
+ unsigned long encoding;
+ void* fde_end;
+ libgcc_object* next;
+};
+
+// undocumented libgcc "struct km_object_info" referenced by KEYMGR_GCC3_DW2_OBJ_LIST
+struct libgcc_object_info {
+ struct libgcc_object* seen_objects;
+ struct libgcc_object* unseen_objects;
+ unsigned spare[2];
+};
+
+
+
+
+namespace lldb_private {
+
+#if !FOR_DYLD
+template <typename A>
+class DwarfFDECache
+{
+public:
+ typedef typename A::pint_t pint_t;
+ static pint_t findFDE(pint_t mh, pint_t pc);
+ static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde);
+ static void removeAllIn(pint_t mh);
+ static void iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));
+private:
+ static void dyldUnloadHook(const struct mach_header* mh, intptr_t vmaddr_slide);
+
+ struct entry { pint_t mh; pint_t ip_start; pint_t ip_end; pint_t fde; };
+
+ // these fields are all static to avoid needing an initializer
+ // there is only one instance of this class per process
+ static pthread_rwlock_t fgLock;
+ static bool fgRegisteredForDyldUnloads;
+ // can't use std::vector<> here because this code must live in libSystem.dylib (which is below libstdc++.dylib)
+ static entry* fgBuffer;
+ static entry* fgBufferUsed;
+ static entry* fgBufferEnd;
+ static entry fgInitialBuffer[64];
+};
+
+template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBuffer = fgInitialBuffer;
+template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBufferUsed = fgInitialBuffer;
+template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBufferEnd = &fgInitialBuffer[64];
+template <typename A> typename DwarfFDECache<A>::entry DwarfFDECache<A>::fgInitialBuffer[64];
+
+template <typename A>
+pthread_rwlock_t DwarfFDECache<A>::fgLock = PTHREAD_RWLOCK_INITIALIZER;
+
+template <typename A>
+bool DwarfFDECache<A>::fgRegisteredForDyldUnloads = false;
+
+
+template <typename A>
+typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc)
+{
+ pint_t result = NULL;
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_rdlock(&fgLock));
+ for(entry* p=fgBuffer; p < fgBufferUsed; ++p) {
+ if ( (mh == p->mh) || (mh == 0) ) {
+ if ( (p->ip_start <= pc) && (pc < p->ip_end) ) {
+ result = p->fde;
+ break;
+ }
+ }
+ }
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
+ //fprintf(stderr, "DwarfFDECache::findFDE(mh=0x%llX, pc=0x%llX) => 0x%llX\n", (uint64_t)mh, (uint64_t)pc, (uint64_t)result);
+ return result;
+}
+
+template <typename A>
+void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde)
+{
+ //fprintf(stderr, "DwarfFDECache::add(mh=0x%llX, ip_start=0x%llX, ip_end=0x%llX, fde=0x%llX) pthread=%p\n",
+ // (uint64_t)mh, (uint64_t)ip_start, (uint64_t)ip_end, (uint64_t)fde, pthread_self());
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock));
+ if ( fgBufferUsed >= fgBufferEnd ) {
+ int oldSize = fgBufferEnd - fgBuffer;
+ int newSize = oldSize*4;
+ entry* newBuffer = (entry*)malloc(newSize*sizeof(entry)); // can't use operator new in libSystem.dylib
+ memcpy(newBuffer, fgBuffer, oldSize*sizeof(entry));
+ //fprintf(stderr, "DwarfFDECache::add() growing buffer to %d\n", newSize);
+ if ( fgBuffer != fgInitialBuffer )
+ free(fgBuffer);
+ fgBuffer = newBuffer;
+ fgBufferUsed = &newBuffer[oldSize];
+ fgBufferEnd = &newBuffer[newSize];
+ }
+ fgBufferUsed->mh = mh;
+ fgBufferUsed->ip_start = ip_start;
+ fgBufferUsed->ip_end = ip_end;
+ fgBufferUsed->fde = fde;
+ ++fgBufferUsed;
+#if !defined (SUPPORT_REMOTE_UNWINDING)
+ if ( !fgRegisteredForDyldUnloads ) {
+ _dyld_register_func_for_remove_image(&dyldUnloadHook);
+ fgRegisteredForDyldUnloads = true;
+ }
+#endif
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
+}
+
+
+
+template <typename A>
+void DwarfFDECache<A>::removeAllIn(pint_t mh)
+{
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock));
+ entry* d=fgBuffer;
+ for(const entry* s=fgBuffer; s < fgBufferUsed; ++s) {
+ if ( s->mh != mh ) {
+ if ( d != s )
+ *d = *s;
+ ++d;
+ }
+ }
+ fgBufferUsed = d;
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
+}
+
+
+template <typename A>
+void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header* mh, intptr_t vmaddr_slide)
+{
+#if !defined (SUPPORT_REMOTE_UNWINDING)
+ removeAllIn((pint_t)mh);
+#endif
+}
+
+template <typename A>
+void DwarfFDECache<A>::iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh))
+{
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock));
+ for(entry* p=fgBuffer; p < fgBufferUsed; ++p) {
+ (*func)(p->ip_start, p->ip_end, p->fde, p->mh);
+ }
+ DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
+}
+#endif // !FOR_DYLD
+
+
+
+
+#define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field))
+
+template <typename A>
+class UnwindSectionHeader {
+public:
+ UnwindSectionHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t version() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, version)); }
+ uint32_t commonEncodingsArraySectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, commonEncodingsArraySectionOffset)); }
+ uint32_t commonEncodingsArrayCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, commonEncodingsArrayCount)); }
+ uint32_t personalityArraySectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, personalityArraySectionOffset)); }
+ uint32_t personalityArrayCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, personalityArrayCount)); }
+ uint32_t indexSectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, indexSectionOffset)); }
+ uint32_t indexCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, indexCount)); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+template <typename A>
+class UnwindSectionIndexArray {
+public:
+ UnwindSectionIndexArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, functionOffset)); }
+ uint32_t secondLevelPagesSectionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, secondLevelPagesSectionOffset)); }
+ uint32_t lsdaIndexArraySectionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, lsdaIndexArraySectionOffset)); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+
+template <typename A>
+class UnwindSectionRegularPageHeader {
+public:
+ UnwindSectionRegularPageHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t kind() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_regular_second_level_page_header, kind)); }
+ uint16_t entryPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_regular_second_level_page_header, entryPageOffset)); }
+ uint16_t entryCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_regular_second_level_page_header, entryCount)); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+
+template <typename A>
+class UnwindSectionRegularArray {
+public:
+ UnwindSectionRegularArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_regular_second_level_entry, index, functionOffset)); }
+ uint32_t encoding(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+
+template <typename A>
+class UnwindSectionCompressedPageHeader {
+public:
+ UnwindSectionCompressedPageHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t kind() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_compressed_second_level_page_header, kind)); }
+ uint16_t entryPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, entryPageOffset)); }
+ uint16_t entryCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, entryCount)); }
+ uint16_t encodingsPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, encodingsPageOffset)); }
+ uint16_t encodingsCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, encodingsCount)); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+
+template <typename A>
+class UnwindSectionCompressedArray {
+public:
+ UnwindSectionCompressedArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t functionOffset(int index) const INLINE { return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( fAddressSpace.get32(fAddr + index*sizeof(uint32_t)) ); }
+ uint16_t encodingIndex(int index) const INLINE { return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( fAddressSpace.get32(fAddr + index*sizeof(uint32_t)) ); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+
+template <typename A>
+class UnwindSectionLsdaArray {
+public:
+ UnwindSectionLsdaArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
+
+ uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, functionOffset)); }
+ int32_t lsdaOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, lsdaOffset)); }
+private:
+ A& fAddressSpace;
+ typename A::pint_t fAddr;
+};
+
+
+template <typename A, typename R>
+class UnwindCursor
+{
+public:
+ UnwindCursor(unw_context_t* context, A& as);
+ virtual ~UnwindCursor() {}
+ virtual bool validReg(int);
+ virtual uint64_t getReg(int);
+ virtual int getReg(int, uint64_t*);
+ virtual int setReg(int, uint64_t);
+ virtual bool validFloatReg(int);
+ virtual double getFloatReg(int);
+ virtual int getFloatReg(int, double*);
+ virtual int setFloatReg(int, double);
+ virtual int step();
+ virtual void getInfo(unw_proc_info_t*);
+ virtual void jumpto();
+ virtual const char* getRegisterName(int num);
+ virtual bool isSignalFrame();
+ virtual bool getFunctionName(char* buf, size_t bufLen, unw_word_t* offset);
+ virtual void setInfoBasedOnIPRegister(bool isReturnAddress=false);
+
+ void operator delete(void* p, size_t size) {}
+
+protected:
+ typedef typename A::pint_t pint_t;
+ typedef uint32_t EncodedUnwindInfo;
+
+ virtual bool getInfoFromCompactEncodingSection(pint_t pc, pint_t mh, pint_t unwindSectionStart);
+ virtual bool getInfoFromDwarfSection(pint_t pc, pint_t mh, pint_t ehSectionStart, uint32_t sectionLength, uint32_t sectionOffsetOfFDE);
+
+ virtual int stepWithDwarfFDE()
+ { return DwarfInstructions<A,R>::stepWithDwarf(fAddressSpace, this->getReg(UNW_REG_IP), fInfo.unwind_info, fRegisters); }
+
+ virtual int stepWithCompactEncoding() { R dummy; return stepWithCompactEncoding(dummy); }
+ int stepWithCompactEncoding(Registers_x86_64&)
+ { return CompactUnwinder_x86_64<A>::stepWithCompactEncoding(fInfo.format, fInfo.start_ip, fAddressSpace, fRegisters); }
+ int stepWithCompactEncoding(Registers_x86&)
+ { return CompactUnwinder_x86<A>::stepWithCompactEncoding(fInfo.format, fInfo.start_ip, fAddressSpace, fRegisters); }
+ int stepWithCompactEncoding(Registers_ppc&)
+ { return UNW_EINVAL; }
+
+#if FOR_DYLD
+ #if __ppc__
+ virtual bool mustUseDwarf() const { return true; }
+ #else
+ virtual bool mustUseDwarf() const { return false; }
+ #endif
+#else
+ virtual bool mustUseDwarf() const { R dummy; uint32_t offset; return dwarfWithOffset(dummy, offset); }
+#endif
+
+ virtual bool dwarfWithOffset(uint32_t& offset) const { R dummy; return dwarfWithOffset(dummy, offset); }
+ virtual bool dwarfWithOffset(Registers_x86_64&, uint32_t& offset) const {
+ if ( (fInfo.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) {
+ offset = (fInfo.format & UNWIND_X86_64_DWARF_SECTION_OFFSET);
+ return true;
+ }
+#if SUPPORT_OLD_BINARIES
+ if ( (fInfo.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_COMPATIBILITY ) {
+ if ( (fInfo.format & UNWIND_X86_64_CASE_MASK) == UNWIND_X86_64_UNWIND_REQUIRES_DWARF ) {
+ offset = 0;
+ return true;
+ }
+ }
+#endif
+ return false;
+ }
+ virtual bool dwarfWithOffset(Registers_x86&, uint32_t& offset) const {
+ if ( (fInfo.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) {
+ offset = (fInfo.format & UNWIND_X86_DWARF_SECTION_OFFSET);
+ return true;
+ }
+#if SUPPORT_OLD_BINARIES
+ if ( (fInfo.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_COMPATIBILITY ) {
+ if ( (fInfo.format & UNWIND_X86_CASE_MASK) == UNWIND_X86_UNWIND_REQUIRES_DWARF ) {
+ offset = 0;
+ return true;
+ }
+ }
+#endif
+ return false;
+ }
+ virtual bool dwarfWithOffset(Registers_ppc&, uint32_t& offset) const { return true; }
+
+
+ virtual compact_unwind_encoding_t dwarfEncoding() const { R dummy; return dwarfEncoding(dummy); }
+ virtual compact_unwind_encoding_t dwarfEncoding(Registers_x86_64&) const { return UNWIND_X86_64_MODE_DWARF; }
+ virtual compact_unwind_encoding_t dwarfEncoding(Registers_x86&) const { return UNWIND_X86_MODE_DWARF; }
+ virtual compact_unwind_encoding_t dwarfEncoding(Registers_ppc&) const { return 0; }
+
+ unw_proc_info_t fInfo;
+ R fRegisters;
+ A& fAddressSpace;
+ bool fUnwindInfoMissing;
+ bool fIsSignalFrame;
+};
+
+typedef UnwindCursor<LocalAddressSpace,Registers_x86> AbstractUnwindCursor;
+
+template <typename A, typename R>
+UnwindCursor<A,R>::UnwindCursor(unw_context_t* context, A& as)
+ : fRegisters(context), fAddressSpace(as), fUnwindInfoMissing(false), fIsSignalFrame(false)
+{
+ COMPILE_TIME_ASSERT( sizeof(UnwindCursor<A,R>) < sizeof(unw_cursor_t) );
+
+ bzero(&fInfo, sizeof(fInfo));
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A,R>::validReg(int regNum)
+{
+ return fRegisters.validRegister(regNum);
+}
+
+template <typename A, typename R>
+uint64_t UnwindCursor<A,R>::getReg(int regNum)
+{
+ return fRegisters.getRegister(regNum);
+}
+
+template <typename A, typename R>
+int UnwindCursor<A,R>::getReg(int regNum, uint64_t *valp)
+{
+ *valp = fRegisters.getRegister(regNum);
+ return UNW_ESUCCESS;
+}
+
+template <typename A, typename R>
+int UnwindCursor<A,R>::setReg(int regNum, uint64_t value)
+{
+ fRegisters.setRegister(regNum, value);
+ return UNW_ESUCCESS;
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A,R>::validFloatReg(int regNum)
+{
+ return fRegisters.validFloatRegister(regNum);
+}
+
+template <typename A, typename R>
+double UnwindCursor<A,R>::getFloatReg(int regNum)
+{
+ return fRegisters.getFloatRegister(regNum);
+}
+
+template <typename A, typename R>
+int UnwindCursor<A,R>::getFloatReg(int regNum, double *valp)
+{
+ *valp = fRegisters.getFloatRegister(regNum);
+ return UNW_ESUCCESS;
+}
+
+template <typename A, typename R>
+int UnwindCursor<A,R>::setFloatReg(int regNum, double value)
+{
+ fRegisters.setFloatRegister(regNum, value);
+ return UNW_ESUCCESS;
+}
+
+template <typename A, typename R>
+void UnwindCursor<A,R>::jumpto()
+{
+#if !defined (SUPPORT_REMOTE_UNWINDING)
+ fRegisters.jumpto();
+#endif
+}
+
+template <typename A, typename R>
+const char* UnwindCursor<A,R>::getRegisterName(int regNum)
+{
+ return fRegisters.getRegisterName(regNum);
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A,R>::isSignalFrame()
+{
+ return fIsSignalFrame;
+}
+
+
+template <typename A, typename R>
+bool UnwindCursor<A,R>::getInfoFromDwarfSection(pint_t pc, pint_t mh, pint_t ehSectionStart, uint32_t sectionLength, uint32_t sectionOffsetOfFDE)
+{
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ bool foundFDE = false;
+ bool foundInCache = false;
+ // if compact encoding table gave offset into dwarf section, go directly there
+ if ( sectionOffsetOfFDE != 0 ) {
+ foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, ehSectionStart+sectionOffsetOfFDE, &fdeInfo, &cieInfo);
+ }
+#if !FOR_DYLD
+ if ( !foundFDE ) {
+ // otherwise, search cache of previously found FDEs
+ pint_t cachedFDE = DwarfFDECache<A>::findFDE(mh, pc);
+ //fprintf(stderr, "getInfoFromDwarfSection(pc=0x%llX) cachedFDE=0x%llX\n", (uint64_t)pc, (uint64_t)cachedFDE);
+ if ( cachedFDE != 0 ) {
+ foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, cachedFDE, &fdeInfo, &cieInfo);
+ foundInCache = foundFDE;
+ //fprintf(stderr, "cachedFDE=0x%llX, foundInCache=%d\n", (uint64_t)cachedFDE, foundInCache);
+ }
+ }
+#endif
+ if ( !foundFDE ) {
+ // still not found, do full scan of __eh_frame section
+ foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, 0, &fdeInfo, &cieInfo);
+ }
+ if ( foundFDE ) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
+ // save off parsed FDE info
+ fInfo.start_ip = fdeInfo.pcStart;
+ fInfo.end_ip = fdeInfo.pcEnd;
+ fInfo.lsda = fdeInfo.lsda;
+ fInfo.handler = cieInfo.personality;
+ fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function
+ fInfo.flags = 0;
+ fInfo.format = dwarfEncoding();
+ fInfo.unwind_info = fdeInfo.fdeStart;
+ fInfo.unwind_info_size = fdeInfo.fdeLength;
+ fInfo.extra = (unw_word_t)mh;
+ if ( !foundInCache && (sectionOffsetOfFDE == 0) ) {
+ // don't add to cache entries the compact encoding table can find quickly
+ //fprintf(stderr, "getInfoFromDwarfSection(pc=0x%0llX), mh=0x%llX, start_ip=0x%0llX, fde=0x%0llX, personality=0x%0llX\n",
+ // (uint64_t)pc, (uint64_t)mh, fInfo.start_ip, fInfo.unwind_info, fInfo.handler);
+#if !FOR_DYLD
+ DwarfFDECache<A>::add(mh, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart);
+#endif
+ }
+ return true;
+ }
+ }
+ //DEBUG_MESSAGE("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc);
+ return false;
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A,R>::getInfoFromCompactEncodingSection(pint_t pc, pint_t mh, pint_t unwindSectionStart)
+{
+ const bool log = false;
+ if ( log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", (uint64_t)pc, (uint64_t)mh);
+
+ const UnwindSectionHeader<A> sectionHeader(fAddressSpace, unwindSectionStart);
+ if ( sectionHeader.version() != UNWIND_SECTION_VERSION )
+ return false;
+
+ // do a binary search of top level index to find page with unwind info
+ uint32_t targetFunctionOffset = pc - mh;
+ const UnwindSectionIndexArray<A> topIndex(fAddressSpace, unwindSectionStart + sectionHeader.indexSectionOffset());
+ uint32_t low = 0;
+ uint32_t high = sectionHeader.indexCount();
+ const uint32_t last = high - 1;
+ while ( low < high ) {
+ uint32_t mid = (low + high)/2;
+ //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", mid, low, high, topIndex.functionOffset(mid));
+ if ( topIndex.functionOffset(mid) <= targetFunctionOffset ) {
+ if ( (mid == last) || (topIndex.functionOffset(mid+1) > targetFunctionOffset) ) {
+ low = mid;
+ break;
+ }
+ else {
+ low = mid+1;
+ }
+ }
+ else {
+ high = mid;
+ }
+ }
+ const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low);
+ const uint32_t firstLevelNextPageFunctionOffset = topIndex.functionOffset(low+1);
+ const pint_t secondLevelAddr = unwindSectionStart+topIndex.secondLevelPagesSectionOffset(low);
+ const pint_t lsdaArrayStartAddr = unwindSectionStart+topIndex.lsdaIndexArraySectionOffset(low);
+ const pint_t lsdaArrayEndAddr = unwindSectionStart+topIndex.lsdaIndexArraySectionOffset(low+1);
+ if ( log ) fprintf(stderr, "\tfirst level search for result index=%d to secondLevelAddr=0x%llX\n",
+ low, (uint64_t)secondLevelAddr);
+ // do a binary search of second level page index
+ uint32_t encoding = 0;
+ pint_t funcStart = 0;
+ pint_t funcEnd = 0;
+ pint_t lsda = 0;
+ pint_t personality = 0;
+ uint32_t pageKind = fAddressSpace.get32(secondLevelAddr);
+ if ( pageKind == UNWIND_SECOND_LEVEL_REGULAR ) {
+ // regular page
+ UnwindSectionRegularPageHeader<A> pageHeader(fAddressSpace, secondLevelAddr);
+ UnwindSectionRegularArray<A> pageIndex(fAddressSpace, secondLevelAddr + pageHeader.entryPageOffset());
+ // binary search looks for entry with e where index[e].offset <= pc < index[e+1].offset
+ if ( log ) fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in regular page starting at secondLevelAddr=0x%llX\n",
+ (uint64_t)targetFunctionOffset, (uint64_t)secondLevelAddr);
+ uint32_t low = 0;
+ uint32_t high = pageHeader.entryCount();
+ while ( low < high ) {
+ uint32_t mid = (low + high)/2;
+ if ( pageIndex.functionOffset(mid) <= targetFunctionOffset ) {
+ if ( mid == (uint32_t)(pageHeader.entryCount()-1) ) {
+ // at end of table
+ low = mid;
+ funcEnd = firstLevelNextPageFunctionOffset + mh;
+ break;
+ }
+ else if ( pageIndex.functionOffset(mid+1) > targetFunctionOffset ) {
+ // next is too big, so we found it
+ low = mid;
+ funcEnd = pageIndex.functionOffset(low+1) + mh;
+ break;
+ }
+ else {
+ low = mid+1;
+ }
+ }
+ else {
+ high = mid;
+ }
+ }
+ encoding = pageIndex.encoding(low);
+ funcStart = pageIndex.functionOffset(low) + mh;
+ if ( pc < funcStart ) {
+ if ( log ) fprintf(stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart, (uint64_t)funcEnd);
+ return false;
+ }
+ if ( pc > funcEnd ) {
+ if ( log ) fprintf(stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart, (uint64_t)funcEnd);
+ return false;
+ }
+ }
+ else if ( pageKind == UNWIND_SECOND_LEVEL_COMPRESSED ) {
+ // compressed page
+ UnwindSectionCompressedPageHeader<A> pageHeader(fAddressSpace, secondLevelAddr);
+ UnwindSectionCompressedArray<A> pageIndex(fAddressSpace, secondLevelAddr + pageHeader.entryPageOffset());
+ const uint32_t targetFunctionPageOffset = targetFunctionOffset - firstLevelFunctionOffset;
+ // binary search looks for entry with e where index[e].offset <= pc < index[e+1].offset
+ if ( log ) fprintf(stderr, "\tbinary search of compressed page starting at secondLevelAddr=0x%llX\n", (uint64_t)secondLevelAddr);
+ uint32_t low = 0;
+ const uint32_t last = pageHeader.entryCount() - 1;
+ uint32_t high = pageHeader.entryCount();
+ while ( low < high ) {
+ uint32_t mid = (low + high)/2;
+ if ( pageIndex.functionOffset(mid) <= targetFunctionPageOffset ) {
+ if ( (mid == last) || (pageIndex.functionOffset(mid+1) > targetFunctionPageOffset) ) {
+ low = mid;
+ break;
+ }
+ else {
+ low = mid+1;
+ }
+ }
+ else {
+ high = mid;
+ }
+ }
+ funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset + mh;
+ if ( low < last )
+ funcEnd = pageIndex.functionOffset(low+1) + firstLevelFunctionOffset + mh;
+ else
+ funcEnd = firstLevelNextPageFunctionOffset + mh;
+ if ( pc < funcStart ) {
+ DEBUG_MESSAGE("malformed __unwind_info, pc=0x%llX not in second level compressed unwind table. funcStart=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart);
+ return false;
+ }
+ if ( pc > funcEnd ) {
+ DEBUG_MESSAGE("malformed __unwind_info, pc=0x%llX not in second level compressed unwind table. funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcEnd);
+ return false;
+ }
+ uint16_t encodingIndex = pageIndex.encodingIndex(low);
+ if ( encodingIndex < sectionHeader.commonEncodingsArrayCount() ) {
+ // encoding is in common table in section header
+ encoding = fAddressSpace.get32(unwindSectionStart+sectionHeader.commonEncodingsArraySectionOffset()+encodingIndex*sizeof(uint32_t));
+ }
+ else {
+ // encoding is in page specific table
+ uint16_t pageEncodingIndex = encodingIndex-sectionHeader.commonEncodingsArrayCount();
+ encoding = fAddressSpace.get32(secondLevelAddr+pageHeader.encodingsPageOffset()+pageEncodingIndex*sizeof(uint32_t));
+ }
+ }
+ else {
+ DEBUG_MESSAGE("malformed __unwind_info at 0x%0llX bad second level page\n", (uint64_t)unwindSectionStart);
+ return false;
+ }
+
+ // look up LSDA, if encoding says function has one
+ if ( encoding & UNWIND_HAS_LSDA ) {
+ UnwindSectionLsdaArray<A> lsdaIndex(fAddressSpace, lsdaArrayStartAddr);
+ uint32_t funcStartOffset = funcStart - mh;
+ uint32_t low = 0;
+ uint32_t high = (lsdaArrayEndAddr-lsdaArrayStartAddr)/sizeof(unwind_info_section_header_lsda_index_entry);
+ // binary search looks for entry with exact match for functionOffset
+ if ( log ) fprintf(stderr, "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", funcStartOffset);
+ while ( low < high ) {
+ uint32_t mid = (low + high)/2;
+ if ( lsdaIndex.functionOffset(mid) == funcStartOffset ) {
+ lsda = lsdaIndex.lsdaOffset(mid) + mh;
+ break;
+ }
+ else if ( lsdaIndex.functionOffset(mid) < funcStartOffset ) {
+ low = mid+1;
+ }
+ else {
+ high = mid;
+ }
+ }
+ if ( lsda == 0 ) {
+ DEBUG_MESSAGE("found encoding 0x%08X with HAS_LSDA bit set for pc=0x%0llX, but lsda table has no entry\n", encoding, (uint64_t)pc);
+ return false;
+ }
+ }
+
+ // extact personality routine, if encoding says function has one
+ uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> (__builtin_ctz(UNWIND_PERSONALITY_MASK));
+ if ( personalityIndex != 0 ) {
+ --personalityIndex; // change 1-based to zero-based index
+ if ( personalityIndex > sectionHeader.personalityArrayCount() ) {
+ DEBUG_MESSAGE("found encoding 0x%08X with personality index %d, but personality table has only %d entires\n",
+ encoding, personalityIndex, sectionHeader.personalityArrayCount());
+ return false;
+ }
+ int32_t personalityDelta = fAddressSpace.get32(unwindSectionStart+sectionHeader.personalityArraySectionOffset()+personalityIndex*sizeof(uint32_t));
+ pint_t personalityPointer = personalityDelta + mh;
+ personality = fAddressSpace.getP(personalityPointer);
+ if (log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), personalityDelta=0x%08X, personality=0x%08llX\n",
+ (uint64_t)pc, personalityDelta, (uint64_t)personality);
+ }
+
+ if (log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n",
+ (uint64_t)pc, encoding, (uint64_t)lsda, (uint64_t)funcStart);
+ fInfo.start_ip = funcStart;
+ fInfo.end_ip = funcEnd;
+ fInfo.lsda = lsda;
+ fInfo.handler = personality;
+ fInfo.gp = 0;
+ fInfo.flags = 0;
+ fInfo.format = encoding;
+ fInfo.unwind_info = 0;
+ fInfo.unwind_info_size = 0;
+ fInfo.extra = mh;
+ return true;
+}
+
+template <typename A, typename R>
+void UnwindCursor<A,R>::setInfoBasedOnIPRegister(bool isReturnAddress)
+{
+ pint_t pc = this->getReg(UNW_REG_IP);
+
+ // if the last line of a function is a "throw" the compile sometimes
+ // emits no instructions after the call to __cxa_throw. This means
+ // the return address is actually the start of the next function.
+ // To disambiguate this, back up the pc when we know it is a return
+ // address.
+ if ( isReturnAddress )
+ --pc;
+
+ // ask address space object to find unwind sections for this pc
+ pint_t mh;
+ pint_t dwarfStart;
+ pint_t dwarfLength;
+ pint_t compactStart;
+ if ( fAddressSpace.findUnwindSections(pc, mh, dwarfStart, dwarfLength, compactStart) ) {
+ // if there is a compact unwind encoding table, look there first
+ if ( compactStart != 0 ) {
+ if ( this->getInfoFromCompactEncodingSection(pc, mh, compactStart) ) {
+#if !FOR_DYLD
+ // found info in table, done unless encoding says to use dwarf
+ uint32_t offsetInDwarfSection;
+ if ( (dwarfStart != 0) && dwarfWithOffset(offsetInDwarfSection) ) {
+ if ( this->getInfoFromDwarfSection(pc, mh, dwarfStart, dwarfLength, offsetInDwarfSection) ) {
+ // found info in dwarf, done
+ return;
+ }
+ }
+#endif
+ // if unwind table has entry, but entry says there is no unwind info, note that
+ if ( fInfo.format == 0 )
+ fUnwindInfoMissing = true;
+
+ // old compact encoding
+ if ( !mustUseDwarf() ) {
+ return;
+ }
+ }
+ }
+#if !FOR_DYLD || __ppc__
+ // if there is dwarf unwind info, look there next
+ if ( dwarfStart != 0 ) {
+ if ( this->getInfoFromDwarfSection(pc, mh, dwarfStart, dwarfLength, 0) ) {
+ // found info in dwarf, done
+ return;
+ }
+ }
+#endif
+ }
+
+#if !FOR_DYLD
+ // the PC is not in code loaded by dyld, look through __register_frame() registered FDEs
+ pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc);
+ if ( cachedFDE != 0 ) {
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ const char* msg = CFI_Parser<A>::decodeFDE(fAddressSpace, cachedFDE, &fdeInfo, &cieInfo);
+ if ( msg == NULL ) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
+ // save off parsed FDE info
+ fInfo.start_ip = fdeInfo.pcStart;
+ fInfo.end_ip = fdeInfo.pcEnd;
+ fInfo.lsda = fdeInfo.lsda;
+ fInfo.handler = cieInfo.personality;
+ fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function
+ fInfo.flags = 0;
+ fInfo.format = dwarfEncoding();
+ fInfo.unwind_info = fdeInfo.fdeStart;
+ fInfo.unwind_info_size = fdeInfo.fdeLength;
+ fInfo.extra = 0;
+ return;
+ }
+ }
+ }
+
+#if !defined (SUPPORT_REMOTE_UNWINDING)
+ // lastly check for old style keymgr registration of dynamically generated FDEs
+
+ // acquire exclusive access to libgcc_object_info
+ libgcc_object_info* head = (libgcc_object_info*)_keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
+ if ( head != NULL ) {
+ // look at each FDE in keymgr
+ for (libgcc_object* ob = head->unseen_objects; ob != NULL; ob = ob->next) {
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ const char* msg = CFI_Parser<A>::decodeFDE(fAddressSpace, (pint_t)ob->fde, &fdeInfo, &cieInfo);
+ if ( msg == NULL ) {
+ // see if this FDE is for a function that includes the pc we are looking for
+ if ( (fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd) ) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
+ // save off parsed FDE info
+ fInfo.start_ip = fdeInfo.pcStart;
+ fInfo.end_ip = fdeInfo.pcEnd;
+ fInfo.lsda = fdeInfo.lsda;
+ fInfo.handler = cieInfo.personality;
+ fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function
+ fInfo.flags = 0;
+ fInfo.format = dwarfEncoding();
+ fInfo.unwind_info = fdeInfo.fdeStart;
+ fInfo.unwind_info_size = fdeInfo.fdeLength;
+ fInfo.extra = 0;
+ _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
+ return;
+ }
+ }
+ }
+ }
+ }
+ // release libgcc_object_info
+ _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
+#endif // !SUPPORT_REMOTE_UNWINDING
+
+#endif // !FOR_DYLD
+
+ // no unwind info, flag that we can't reliable unwind
+ fUnwindInfoMissing = true;
+}
+
+
+template <typename A, typename R>
+int UnwindCursor<A,R>::step()
+{
+ // bottom of stack is defined as when no more unwind info
+ if ( fUnwindInfoMissing )
+ return UNW_STEP_END;
+
+ // apply unwinding to register set
+ int result;
+ if ( this->mustUseDwarf() )
+ result = this->stepWithDwarfFDE();
+ else
+ result = this->stepWithCompactEncoding();
+
+ // update info based on new PC
+ if ( result == UNW_STEP_SUCCESS ) {
+ this->setInfoBasedOnIPRegister(true);
+ if ( fUnwindInfoMissing )
+ return UNW_STEP_END;
+ }
+
+ return result;
+}
+
+
+template <typename A, typename R>
+void UnwindCursor<A,R>::getInfo(unw_proc_info_t* info)
+{
+ *info = fInfo;
+}
+
+
+template <typename A, typename R>
+bool UnwindCursor<A,R>::getFunctionName(char* buf, size_t bufLen, unw_word_t* offset)
+{
+ return fAddressSpace.findFunctionName(this->getReg(UNW_REG_IP), buf, bufLen, offset);
+}
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+template <typename A, typename R>
+class RemoteUnwindCursor : UnwindCursor<A,R>
+{
+public:
+ typedef typename A::pint_t pint_t;
+ RemoteUnwindCursor(A& as, unw_context_t* regs, void* arg);
+ virtual bool validReg(int);
+ virtual int getReg(int r, uint64_t*);
+ virtual int setReg(int, uint64_t);
+ virtual bool validFloatReg(int);
+ virtual int getFloatReg(int, double*);
+ virtual int setFloatReg(int, double);
+ virtual const char* getRegisterName(int);
+ virtual int step();
+ virtual void setRemoteContext(void*);
+ virtual bool remoteUnwindCursor () const {return this->fAddressSpace.getRemoteProcInfo() != NULL; }
+ virtual int endOfPrologueInsns(unw_word_t, unw_word_t, unw_word_t*);
+ void operator delete(void* p, size_t size) {}
+private:
+ virtual bool caller_regno_to_unwind_regno (int, int&);
+
+ bool fIsLeafFrame;
+ bool fIsFirstFrame;
+ void* fArg;
+};
+
+typedef RemoteUnwindCursor<LocalAddressSpace,Registers_x86_64> AbstractRemoteUnwindCursor;
+
+template <typename A, typename R>
+RemoteUnwindCursor<A,R>::RemoteUnwindCursor(A& as, unw_context_t* regs, void* arg)
+ : UnwindCursor<A,R>::UnwindCursor(regs, as), fIsFirstFrame (false), fIsLeafFrame(false), fArg(arg)
+{
+ COMPILE_TIME_ASSERT( sizeof(RemoteUnwindCursor<A,R>) < sizeof(unw_cursor_t) );
+}
+
+template <typename A, typename R>
+bool RemoteUnwindCursor<A,R>::validReg(int r)
+{
+ int unwind_regno;
+ if (!caller_regno_to_unwind_regno(r, unwind_regno))
+ return false;
+ return UnwindCursor<A,R>::fRegisters.validRegister(unwind_regno);
+}
+
+template <typename A, typename R>
+int RemoteUnwindCursor<A,R>::getReg(int regNum, uint64_t *valp)
+{
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo ();
+ if (procinfo == NULL) {
+ ABORT("getRemoteReg called with a local unwind, use getReg instead.");
+ }
+
+ RemoteRegisterMap *regmap = procinfo->getRegisterMap ();
+ int unwind_regno;
+ if (regmap->caller_regno_to_unwind_regno (regNum, unwind_regno) == false)
+ return UNW_EBADREG;
+ regNum = unwind_regno;
+
+ // we always return nonvolatile registers. If we have the entire register state available
+ // for this frame then we can return any register requested.
+ if (regmap->nonvolatile_reg_p (regNum) == true || fIsLeafFrame == true) {
+ return this->UnwindCursor<A,R>::getReg (unwind_regno, valp);
+ }
+ return UNW_EREGUNAVAILABLE;
+}
+
+template <typename A, typename R>
+int RemoteUnwindCursor<A,R>::setReg(int regNum, uint64_t val)
+{
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo ();
+ if (procinfo == NULL) {
+ ABORT("setRemoteReg called with a local unwind, use setReg instead.");
+ }
+
+ RemoteRegisterMap *regmap = procinfo->getRegisterMap ();
+ int unwind_regno;
+ if (regmap->caller_regno_to_unwind_regno (regNum, unwind_regno) == false)
+ return UNW_EBADREG;
+ regNum = unwind_regno;
+
+ // Only allow the registers to be set if the unwind cursor is pointing to the
+ // first frame. We need to track where registers were retrieved from in memory
+ // in every other frame. Until then, we prohibit register setting in all but
+ // the first frame.
+ if (fIsFirstFrame) {
+ return this->setReg(unwind_regno, val);
+ }
+ return UNW_EREGUNAVAILABLE;
+}
+
+template <typename A, typename R>
+bool RemoteUnwindCursor<A,R>::validFloatReg(int r)
+{
+ int unwind_regno;
+ if (!caller_regno_to_unwind_regno(r, unwind_regno))
+ return false;
+ return UnwindCursor<A,R>::fRegisters.validFloatRegister(unwind_regno);
+}
+
+template <typename A, typename R>
+int RemoteUnwindCursor<A,R>::getFloatReg(int regNum, double *valp)
+{
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo ();
+ if (procinfo == NULL) {
+ ABORT("getRemoteReg called with a local unwind, use getReg instead.");
+ }
+
+ RemoteRegisterMap *regmap = procinfo->getRegisterMap ();
+ int unwind_regno;
+ if (regmap->caller_regno_to_unwind_regno (regNum, unwind_regno) == false)
+ return UNW_EBADREG;
+ regNum = unwind_regno;
+
+ // we always return nonvolatile registers. If we have the entire register state available
+ // for this frame then we can return any register requested.
+ if (regmap->nonvolatile_reg_p (regNum) == true || fIsLeafFrame == true) {
+ return this->UnwindCursor<A,R>::getFloatReg (unwind_regno, valp);
+ }
+ return UNW_EREGUNAVAILABLE;
+}
+
+template <typename A, typename R>
+int RemoteUnwindCursor<A,R>::setFloatReg(int regNum, double val)
+{
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo ();
+ if (procinfo == NULL) {
+ ABORT("setRemoteReg called with a local unwind, use setReg instead.");
+ }
+
+ RemoteRegisterMap *regmap = procinfo->getRegisterMap ();
+ int unwind_regno;
+ if (regmap->caller_regno_to_unwind_regno (regNum, unwind_regno) == false)
+ return UNW_EBADREG;
+ regNum = unwind_regno;
+
+ // Only allow the registers to be set if the unwind cursor is pointing to the
+ // first frame. We need to track where registers were retrieved from in memory
+ // in every other frame. Until then, we prohibit register setting in all but
+ // the first frame.
+ if (fIsFirstFrame) {
+ return this->setFloatReg(unwind_regno, val);
+ }
+ return UNW_EREGUNAVAILABLE;
+}
+
+
+template <typename A, typename R>
+const char* RemoteUnwindCursor<A,R>::getRegisterName(int r)
+{
+ int t;
+ if (!this->caller_regno_to_unwind_regno(r, t))
+ return NULL;
+ r = t;
+ return this->UnwindCursor<A,R>::getRegisterName(r);
+}
+
+template <typename A, typename R>
+int RemoteUnwindCursor<A,R>::step()
+{
+ pint_t pc = this->UnwindCursor<A,R>::getReg(UNW_REG_IP);
+ pint_t sp = this->UnwindCursor<A,R>::getReg(UNW_REG_SP);
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo();
+ bool frame_is_sigtramp = false;
+ bool frame_is_inferior_function_call_dummy = false;
+
+ if (procinfo == NULL) {
+ ABORT("stepRemote called with local unwind, use step() instead.");
+ return UNW_EUNSPEC;
+ }
+ struct timeval *step_remote = procinfo->timestamp_start();
+ procinfo->logVerbose ("stepRemote stepping out of frame with pc value 0x%llx", pc);
+
+ // We'll be off of the first frame once we finish this step.
+ fIsFirstFrame = false;
+
+ if (UnwindCursor<A,R>::fAddressSpace.accessors()
+ && UnwindCursor<A,R>::fAddressSpace.accessors()->proc_is_sigtramp != NULL
+ && UnwindCursor<A,R>::fAddressSpace.accessors()->proc_is_sigtramp (procinfo->wrap(), pc, fArg)) {
+ frame_is_sigtramp = true;
+ }
+ if (UnwindCursor<A,R>::fAddressSpace.accessors()
+ && UnwindCursor<A,R>::fAddressSpace.accessors()->proc_is_inferior_function_call != NULL
+ && UnwindCursor<A,R>::fAddressSpace.accessors()->proc_is_inferior_function_call (procinfo->wrap(), pc, sp, fArg)) {
+ frame_is_inferior_function_call_dummy = true;
+ }
+
+ // If the function we're unwinding can't be a leaf function,
+ // use the eh_frame or compact unwind info if possible.
+ // The caller should pass couldBeLeafFunc == 0 on the first step of a new context
+ // but we can't trust them in that.
+
+ if ((fIsLeafFrame == false && frame_is_inferior_function_call_dummy == false)
+ || frame_is_sigtramp) {
+ R saved_registers(UnwindCursor<A,R>::fRegisters);
+ this->setInfoBasedOnIPRegister(true);
+ // bottom of stack is defined as when no more unwind info
+ if ( !UnwindCursor<A,R>::fUnwindInfoMissing ) {
+ int result;
+ const char *method;
+ if ( this->mustUseDwarf() ) {
+ result = this->stepWithDwarfFDE();
+ method = "dwarf";
+ }
+ else {
+ result = this->stepWithCompactEncoding();
+ method = "compact unwind";
+ }
+ if ( result == UNW_STEP_SUCCESS ) {
+ procinfo->logInfo ("Stepped via %s", method);
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ if (frame_is_sigtramp)
+ fIsLeafFrame = true;
+ return result;
+ }
+ }
+ UnwindCursor<A,R>::fRegisters = saved_registers;
+ }
+
+ if (frame_is_sigtramp || frame_is_inferior_function_call_dummy)
+ fIsLeafFrame = true; // this will be true once we complete this stepRemote()
+ else
+ fIsLeafFrame = false;
+
+ if (frame_is_inferior_function_call_dummy) {
+ if (stepOutOfDebuggerDummyFrame (UnwindCursor<A,R>::fAddressSpace, UnwindCursor<A,R>::fRegisters, procinfo, pc, sp, fArg) == UNW_STEP_SUCCESS) {
+ procinfo->logInfo ("Stepped via stepOutOfDebuggerDummyFrame");
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ return UNW_STEP_SUCCESS;
+ }
+ }
+
+ // If we haven't already seen this function we'll need to get the function bounds via
+ // eh frame info (if available) - it's the most accurate function bounds in a
+ // stripped binary. After that we'll ask the driver program (via the get_proc_bounds accessor).
+
+ if (procinfo->haveProfile (pc) == false) {
+
+ uint64_t text_start, text_end, eh_frame_start, eh_frame_len, compact_unwind_start, mh;
+ uint64_t start_addr, end_addr;
+ if (pc == 0) {
+ int ret = stepByArchitectureDefault (UnwindCursor<A,R>::fAddressSpace, UnwindCursor<A,R>::fRegisters, pc);
+ procinfo->logInfo ("Stepped via stepByArchitectureDefault");
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ return ret;
+ }
+
+ // If the address is not contained in any image's address range either we've walked off
+ // the stack into random memory or we're backtracing through jit'ed code on the heap.
+ // Let's assume the latter and follow the architecture's default stack walking scheme.
+
+ if (!procinfo->getImageAddresses (pc, mh, text_start, text_end, eh_frame_start, eh_frame_len, compact_unwind_start, fArg)) {
+ int ret = stepByArchitectureDefault (UnwindCursor<A,R>::fAddressSpace, UnwindCursor<A,R>::fRegisters, pc);
+ procinfo->logInfo ("Stepped via stepByArchitectureDefault");
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ return ret;
+ }
+ if (procinfo->haveFuncBounds (mh) == false) {
+ struct timeval *get_func_bounds = procinfo->timestamp_start();
+ std::vector<FuncBounds> func_bounds;
+ // CFI entries are usually around 38 bytes but under-estimate a bit
+ // because we're not distinguishing between CIEs and FDEs.
+ if (eh_frame_len > 0)
+ func_bounds.reserve (eh_frame_len / 16);
+ if (procinfo->getCachingPolicy() != UNW_CACHE_NONE) {
+ // cache the entire eh frame section - we'll need to read the whole
+ // thing anyway so we might as well save it.
+ uint8_t *eh_buf = (uint8_t *)malloc (eh_frame_len);
+ if (UnwindCursor<A,R>::fAddressSpace.getBytes (eh_frame_start, eh_frame_len, eh_buf) == 0)
+ return UNW_EUNSPEC;
+ RemoteMemoryBlob *ehmem = new RemoteMemoryBlob(eh_buf, free, eh_frame_start, eh_frame_len, mh, NULL);
+ procinfo->addMemBlob (ehmem);
+ }
+
+ if (CFI_Parser<A>::functionFuncBoundsViaFDE(UnwindCursor<A,R>::fAddressSpace, eh_frame_start, eh_frame_len, func_bounds)) {
+ procinfo->addFuncBounds(mh, func_bounds);
+ procinfo->logVerbose ("Added %d function bounds", (int) func_bounds.size());
+ procinfo->timestamp_stop (get_func_bounds, "getting function bounds from EH frame FDEs");
+ }
+ }
+ if (procinfo->findStartAddr (pc, start_addr, end_addr)) {
+ // If end_addr is 0, we might be looking at the final function in this binary image
+ if (start_addr != 0 && end_addr == 0)
+ end_addr = text_end;
+ procinfo->logVerbose ("Got function bounds from func bounds vector, 0x%llx-0x%llx", start_addr, end_addr);
+ } else {
+ if (UnwindCursor<A,R>::fAddressSpace.accessors()->get_proc_bounds (procinfo->wrap(), pc, &start_addr, &end_addr, fArg) != UNW_ESUCCESS) {
+ int ret = stepByArchitectureDefault (UnwindCursor<A,R>::fAddressSpace, UnwindCursor<A,R>::fRegisters, pc);
+ procinfo->logInfo ("Stepped via stepByArchitectureDefault");
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ return ret;
+ }
+ else {
+ procinfo->logVerbose ("Got function bounds from get_proc_bounds callback, 0x%llx-0x%llx", start_addr, end_addr);
+ }
+ }
+ if (start_addr != 0) {
+ procinfo->addProfile (UnwindCursor<A,R>::fAddressSpace.accessors(), UnwindCursor<A,R>::fAddressSpace.wrap(), start_addr, end_addr, fArg);
+ }
+ }
+
+ RemoteUnwindProfile *profile = procinfo->findProfile (pc);
+ if (profile == NULL)
+ return UNW_ENOINFO;
+
+ int retval = stepWithAssembly (UnwindCursor<A,R>::fAddressSpace, pc, profile, UnwindCursor<A,R>::fRegisters);
+ if (retval >= 0) {
+ procinfo->logInfo ("Stepped via stepWithAssembly");
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ return retval;
+ }
+
+ retval = stepByArchitectureDefault (UnwindCursor<A,R>::fAddressSpace, UnwindCursor<A,R>::fRegisters, pc);
+ procinfo->logInfo ("Stepped via stepByArchitectureDefault");
+ procinfo->timestamp_stop (step_remote, "stepRemote");
+ return retval;
+}
+
+template <typename A, typename R>
+void RemoteUnwindCursor<A,R>::setRemoteContext(void *arg)
+{
+ // fill in the register state for the currently executing frame.
+ getRemoteContext (UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo(), UnwindCursor<A,R>::fRegisters, arg);
+
+ // Flag that this unwind cursor is pointing at the zeroth frame. We don't
+ // want to use compact unwind info / eh frame info to unwind out of this
+ // frame.
+
+ fIsLeafFrame = true;
+ fIsFirstFrame = true;
+}
+
+// This needs to be done in many of the functions and in libuwind.cxx in one or two
+// places so I'm defining a convenience method.
+template <typename A, typename R>
+bool RemoteUnwindCursor<A,R>::caller_regno_to_unwind_regno (int caller_regno, int& unwind_regno)
+{
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo ();
+ if (procinfo == NULL) {
+ unwind_regno = caller_regno;
+ return true;
+ }
+ if (procinfo->getRegisterMap()->caller_regno_to_unwind_regno (caller_regno, unwind_regno))
+ return true;
+ return false;
+}
+
+template <typename A, typename R>
+int RemoteUnwindCursor<A,R>::endOfPrologueInsns (unw_word_t start, unw_word_t end, unw_word_t *endofprologue)
+{
+ RemoteProcInfo *procinfo = UnwindCursor<A,R>::fAddressSpace.getRemoteProcInfo();
+ *endofprologue = start;
+ if (procinfo == NULL) {
+ ABORT("findEndOfPrologueSetup called with local unwind.");
+ return UNW_EUNSPEC;
+ }
+ if (procinfo->haveProfile (start) == false) {
+ uint64_t text_start, text_end, eh_frame_start, eh_frame_len, compact_unwind_start, mh;
+ if (!procinfo->getImageAddresses (start, mh, text_start, text_end, eh_frame_start, eh_frame_len, compact_unwind_start, fArg))
+ return UNW_EUNSPEC;
+ if (end == 0) {
+ if (procinfo->haveFuncBounds (mh) == false) {
+ std::vector<FuncBounds> func_bounds;
+ // CFI entries are usually around 38 bytes but under-estimate a bit
+ // because we're not distinguishing between CIEs and FDEs.
+ if (eh_frame_len > 0)
+ func_bounds.reserve (eh_frame_len / 16);
+ if (procinfo->getCachingPolicy() != UNW_CACHE_NONE) {
+ // cache the entire eh frame section - we'll need to read the whole
+ // thing anyway so we might as well save it.
+ uint8_t *eh_buf = (uint8_t *)malloc (eh_frame_len);
+ if (UnwindCursor<A,R>::fAddressSpace.getBytes (eh_frame_start, eh_frame_len, eh_buf) == 0)
+ return UNW_EUNSPEC;
+ RemoteMemoryBlob *ehmem = new RemoteMemoryBlob(eh_buf, free, eh_frame_start, eh_frame_len, mh, NULL);
+ procinfo->addMemBlob (ehmem);
+ }
+ if (CFI_Parser<A>::functionFuncBoundsViaFDE(UnwindCursor<A,R>::fAddressSpace, eh_frame_start, eh_frame_len, func_bounds)) {
+ procinfo->addFuncBounds(mh, func_bounds);
+ }
+ }
+ uint64_t bounded_start, bounded_end;
+ if (procinfo->findStartAddr (start, bounded_start, bounded_end)) {
+ end = bounded_end;
+ } else {
+ if (UnwindCursor<A,R>::fAddressSpace.accessors()->get_proc_bounds (procinfo->wrap(), start, &bounded_start, &bounded_end, fArg) != UNW_ESUCCESS)
+ if (bounded_end != 0)
+ end = bounded_end;
+ }
+ }
+ if (procinfo->addProfile (UnwindCursor<A,R>::fAddressSpace.accessors(), UnwindCursor<A,R>::fAddressSpace.wrap(), start, end, fArg) == false)
+ return UNW_EUNSPEC;
+ }
+ RemoteUnwindProfile *profile = procinfo->findProfile (start);
+ if (profile == NULL)
+ return UNW_ENOINFO;
+ *endofprologue = profile->fFirstInsnPastPrologue;
+ return UNW_ESUCCESS;
+}
+
+#endif // SUPPORT_REMOTE_UNWINDING
+
+
+}; // namespace lldb_private
+
+
+#endif // __UNWINDCURSOR_HPP__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1-gcc-ext.c b/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1-gcc-ext.c
new file mode 100644
index 00000000000..7103c719ba2
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1-gcc-ext.c
@@ -0,0 +1,282 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- UnwindLevel1-gcc-ext.c ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/*
+ * Implements gcc extensions to the C++ ABI Exception Handling Level 1 as documented at:
+ * <http://www.codesourcery.com/cxx-abi/abi-eh.html>
+ * using libunwind
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libunwind.h"
+#include "unwind.h"
+#include "libunwind_priv.h"
+#include "InternalMacros.h"
+
+
+#if __ppc__ || __i386__ || __x86_64__
+
+//
+// Called by __cxa_rethrow()
+//
+EXPORT _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n", exception_object, exception_object->private_1);
+ // if this is non-forced and a stopping place was found, then this is a re-throw
+ // call _Unwind_RaiseException() as if this was a new exception
+ if ( exception_object->private_1 == 0 )
+ _Unwind_RaiseException(exception_object);
+
+ // call through to _Unwind_Resume() which distiguishes between forced and regular exceptions
+ _Unwind_Resume(exception_object);
+ ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException() which unexpectedly returned");
+}
+
+
+
+//
+// Called by personality handler during phase 2 to get base address for data relative encodings
+//
+EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context)
+{
+ DEBUG_PRINT_API("_Unwind_GetDataRelBase(context=%p)\n", context);
+ ABORT("_Unwind_GetDataRelBase() not implemented");
+}
+
+//
+// Called by personality handler during phase 2 to get base address for text relative encodings
+//
+EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context)
+{
+ DEBUG_PRINT_API("_Unwind_GetTextRelBase(context=%p)\n", context);
+ ABORT("_Unwind_GetTextRelBase() not implemented");
+}
+
+
+
+//
+// Scans unwind information to find the function that contains the
+// specified code address "pc".
+//
+EXPORT void* _Unwind_FindEnclosingFunction(void* pc)
+{
+ DEBUG_PRINT_API("_Unwind_FindEnclosingFunction(pc=%p)\n", pc);
+ ABORT("_Unwind_FindEnclosingFunction() not implemented");
+}
+
+
+//
+// Walk every frame and call trace function at each one. If trace function
+// returns anything other than _URC_NO_REASON, then walk is terminated.
+//
+EXPORT _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn callback, void* ref)
+{
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_getcontext(&uc);
+ unw_init_local(&cursor, &uc);
+
+ DEBUG_PRINT_API("_Unwind_Backtrace(callback=%p)\n", callback);
+
+ // walk each frame
+ while ( true ) {
+
+ // ask libuwind to get next frame (skip over first frame which is _Unwind_Backtrace())
+ if ( unw_step(&cursor) <= 0 ) {
+ DEBUG_PRINT_UNWINDING(" _backtrace: ended because cursor reached bottom of stack, returning %d\n", _URC_END_OF_STACK);
+ return _URC_END_OF_STACK;
+ }
+
+ // debugging
+ if ( DEBUG_PRINT_UNWINDING_TEST ) {
+ char functionName[512];
+ unw_proc_info_t frameInfo;
+ unw_word_t offset;
+ unw_get_proc_name(&cursor, functionName, 512, &offset);
+ unw_get_proc_info(&cursor, &frameInfo);
+ DEBUG_PRINT_UNWINDING(" _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p\n",
+ frameInfo.start_ip, functionName, frameInfo.lsda, &cursor);
+ }
+
+ // call trace function with this frame
+ _Unwind_Reason_Code result = (*callback)((struct _Unwind_Context*)(&cursor), ref);
+ if ( result != _URC_NO_REASON ) {
+ DEBUG_PRINT_UNWINDING(" _backtrace: ended because callback returned %d\n", result);
+ return result;
+ }
+ }
+}
+
+
+//
+// Find dwarf unwind info for an address 'pc' in some function.
+//
+EXPORT const void* _Unwind_Find_FDE(const void* pc, struct dwarf_eh_bases* bases)
+{
+ // This is slow, but works.
+ // We create an unwind cursor then alter the IP to be pc
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_proc_info_t info;
+ unw_getcontext(&uc);
+ unw_init_local(&cursor, &uc);
+ unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long)pc);
+ unw_get_proc_info(&cursor, &info);
+ bases->tbase = info.extra;
+ bases->dbase = 0; // dbase not used on Mac OS X
+ bases->func = info.start_ip;
+ DEBUG_PRINT_API("_Unwind_Find_FDE(pc=%p) => %p\n", pc, (void*)(long)info.unwind_info);
+ return (void*)(long)info.unwind_info;
+}
+
+
+
+EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context* context)
+{
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_word_t result;
+ unw_get_reg(cursor, UNW_REG_SP, &result);
+ DEBUG_PRINT_API("_Unwind_GetCFA(context=%p) => 0x%llX\n", context, (uint64_t)result);
+ return result;
+}
+
+
+//
+// Called by personality handler during phase 2 to get instruction pointer.
+// ipBefore is a boolean that says if IP is already adjusted to be the call
+// site address. Normally IP is the return address.
+//
+EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore)
+{
+ DEBUG_PRINT_API("_Unwind_GetIPInfo(context=%p)\n", context);
+ *ipBefore = 0;
+ return _Unwind_GetIP(context);
+}
+
+
+//
+// Called by programs with dynamic code generators that want
+// to register a dynamically generated FDE.
+// This function has existed on Mac OS X since 10.4, but
+// never worked before.
+//
+EXPORT void __register_frame(const void* fde)
+{
+ DEBUG_PRINT_API("__register_frame(%p)\n", fde);
+ _unw_add_dynamic_fde((unw_word_t)(uintptr_t)fde);
+}
+
+
+//
+// Called by programs with dynamic code generators that want
+// to unregister a dynamically generated FDE.
+// This function has existed on Mac OS X since 10.4, but
+// never worked before.
+//
+EXPORT void __deregister_frame(const void* fde)
+{
+ DEBUG_PRINT_API("__deregister_frame(%p)\n", fde);
+ _unw_remove_dynamic_fde((unw_word_t)(uintptr_t)fde);
+}
+
+
+
+//
+// The following register/deregister functions are gcc extensions.
+// They have existed on Mac OS X, but have never worked because Mac OS X
+// before 10.6 used keymgr to track known FDEs, but these functions
+// never got updated to use keymgr.
+// For now, we implement these as do-nothing functions to keep any existing
+// applications working. We also add the not in 10.6 symbol so that nwe
+// application won't be able to use them.
+//
+
+EXPORT void __register_frame_info_bases(const void* fde, void* ob, void* tb, void* db)
+{
+ DEBUG_PRINT_API("__register_frame_info_bases(%p,%p, %p, %p)\n", fde, ob, tb, db);
+ // do nothing, this function never worked in Mac OS X
+}
+
+EXPORT void __register_frame_info(const void* fde, void* ob)
+{
+ DEBUG_PRINT_API("__register_frame_info(%p, %p)\n", fde, ob);
+ // do nothing, this function never worked in Mac OS X
+}
+
+
+EXPORT void __register_frame_info_table_bases(const void* fde, void* ob, void* tb, void* db)
+{
+ DEBUG_PRINT_API("__register_frame_info_table_bases(%p,%p, %p, %p)\n", fde, ob, tb, db);
+ // do nothing, this function never worked in Mac OS X
+}
+
+EXPORT void __register_frame_info_table(const void* fde, void* ob)
+{
+ DEBUG_PRINT_API("__register_frame_info_table(%p, %p)\n", fde, ob);
+ // do nothing, this function never worked in Mac OS X
+}
+
+EXPORT void __register_frame_table(const void* fde)
+{
+ DEBUG_PRINT_API("__register_frame_table(%p)\n", fde);
+ // do nothing, this function never worked in Mac OS X
+}
+
+EXPORT void* __deregister_frame_info(const void* fde)
+{
+ DEBUG_PRINT_API("__deregister_frame_info(%p)\n", fde);
+ // do nothing, this function never worked in Mac OS X
+ return NULL;
+}
+
+EXPORT void* __deregister_frame_info_bases(const void* fde)
+{
+ DEBUG_PRINT_API("__deregister_frame_info_bases(%p)\n", fde);
+ // do nothing, this function never worked in Mac OS X
+ return NULL;
+}
+
+
+
+
+//
+// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in earlier versions
+//
+NOT_HERE_BEFORE_10_6(_Unwind_Backtrace)
+NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction)
+NOT_HERE_BEFORE_10_6(_Unwind_GetCFA)
+NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase)
+NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase)
+NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow)
+NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo)
+
+NOT_HERE_BEFORE_10_6(__register_frame)
+NOT_HERE_BEFORE_10_6(__deregister_frame)
+
+
+//
+// symbols in libSystem.dylib for compatibility, but we don't want any new code using them
+//
+NEVER_HERE(__register_frame_info_bases)
+NEVER_HERE(__register_frame_info)
+NEVER_HERE(__register_frame_info_table_bases)
+NEVER_HERE(__register_frame_info_table)
+NEVER_HERE(__register_frame_table)
+NEVER_HERE(__deregister_frame_info)
+NEVER_HERE(__deregister_frame_info_bases)
+
+
+#endif // __ppc__ || __i386__ || __x86_64__
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1.c b/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1.c
new file mode 100644
index 00000000000..3aa2b6f552c
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/UnwindLevel1.c
@@ -0,0 +1,443 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- UnwindLevel1.c ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/*
+ *
+ * Implements C++ ABI Exception Handling Level 1 as documented at:
+ * <http://www.codesourcery.com/cxx-abi/abi-eh.html>
+ * using libunwind
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libunwind.h"
+#include "unwind.h"
+#include "InternalMacros.h"
+
+#if __ppc__ || __i386__ || __x86_64__
+
+static _Unwind_Reason_Code unwind_phase1(unw_context_t* uc, struct _Unwind_Exception* exception_object)
+{
+ unw_cursor_t cursor1;
+ unw_init_local(&cursor1, uc);
+
+ // walk each frame looking for a place to stop
+ for (bool handlerNotFound = true; handlerNotFound; ) {
+
+ // ask libuwind to get next frame (skip over first which is _Unwind_RaiseException)
+ int stepResult = unw_step(&cursor1);
+ if ( stepResult == 0 ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
+ return _URC_END_OF_STACK;
+ }
+ else if ( stepResult < 0 ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+
+ // see if frame has code to run (has personality routine)
+ unw_proc_info_t frameInfo;
+ unw_word_t sp;
+ if ( unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+
+ // debugging
+ if ( DEBUG_PRINT_UNWINDING_TEST ) {
+ char functionName[512];
+ unw_word_t offset;
+ if ( (unw_get_proc_name(&cursor1, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
+ strcpy(functionName, ".anonymous.");
+ unw_word_t pc;
+ unw_get_reg(&cursor1, UNW_REG_IP, &pc);
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, lsda=0x%llX, personality=0x%llX\n",
+ exception_object, pc, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler);
+ }
+
+ // if there is a personality routine, ask it if it will want to stop at this frame
+ if ( frameInfo.handler != 0 ) {
+ __personality_routine p = (__personality_routine)(long)(frameInfo.handler);
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): calling personality function %p\n", exception_object, p);
+ _Unwind_Reason_Code personalityResult = (*p)(1, _UA_SEARCH_PHASE,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)(&cursor1));
+ switch ( personalityResult ) {
+ case _URC_HANDLER_FOUND:
+ // found a catch clause or locals that need destructing in this frame
+ // stop search and remember stack pointer at the frame
+ handlerNotFound = false;
+ unw_get_reg(&cursor1, UNW_REG_SP, &sp);
+ exception_object->private_2 = sp;
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND\n", exception_object);
+ return _URC_NO_REASON;
+
+ case _URC_CONTINUE_UNWIND:
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
+ // continue unwinding
+ break;
+
+ default:
+ // something went wrong
+ DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+ }
+ }
+ return _URC_NO_REASON;
+}
+
+
+static _Unwind_Reason_Code unwind_phase2(unw_context_t* uc, struct _Unwind_Exception* exception_object)
+{
+ unw_cursor_t cursor2;
+ unw_init_local(&cursor2, uc);
+
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
+
+ // walk each frame until we reach where search phase said to stop
+ while ( true ) {
+
+ // ask libuwind to get next frame (skip over first which is _Unwind_RaiseException)
+ int stepResult = unw_step(&cursor2);
+ if ( stepResult == 0 ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
+ return _URC_END_OF_STACK;
+ }
+ else if ( stepResult < 0 ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // get info about this frame
+ unw_word_t sp;
+ unw_proc_info_t frameInfo;
+ unw_get_reg(&cursor2, UNW_REG_SP, &sp);
+ if ( unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // debugging
+ if ( DEBUG_PRINT_UNWINDING_TEST ) {
+ char functionName[512];
+ unw_word_t offset;
+ if ( (unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
+ strcpy(functionName, ".anonymous.");
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, lsda=0x%llX, personality=0x%llX\n",
+ exception_object, frameInfo.start_ip, functionName, sp, frameInfo.lsda, frameInfo.handler);
+ }
+
+ // if there is a personality routine, tell it we are unwinding
+ if ( frameInfo.handler != 0 ) {
+ __personality_routine p = (__personality_routine)(long)(frameInfo.handler);
+ _Unwind_Action action = _UA_CLEANUP_PHASE;
+ if ( sp == exception_object->private_2 )
+ action = (_Unwind_Action)(_UA_CLEANUP_PHASE|_UA_HANDLER_FRAME); // tell personality this was the frame it marked in phase 1
+ _Unwind_Reason_Code personalityResult = (*p)(1, action,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)(&cursor2));
+ switch ( personalityResult ) {
+ case _URC_CONTINUE_UNWIND:
+ // continue unwinding
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
+ if ( sp == exception_object->private_2 ) {
+ // phase 1 said we would stop at this frame, but we did not...
+ ABORT("during phase1 personality function said it would stop here, but now if phase2 it did not stop here");
+ }
+ break;
+ case _URC_INSTALL_CONTEXT:
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", exception_object);
+ // personality routine says to transfer control to landing pad
+ // we may get control back if landing pad calls _Unwind_Resume()
+ if ( DEBUG_PRINT_UNWINDING_TEST ) {
+ unw_word_t pc;
+ unw_word_t sp;
+ unw_get_reg(&cursor2, UNW_REG_IP, &pc);
+ unw_get_reg(&cursor2, UNW_REG_SP, &sp);
+ DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering user code with ip=0x%llX, sp=0x%llX\n", exception_object, pc, sp);
+ }
+ unw_resume(&cursor2);
+ // unw_resume() only returns if there was an error
+ return _URC_FATAL_PHASE2_ERROR;
+ default:
+ // something went wrong
+ DEBUG_MESSAGE("personality function returned unknown result %d", personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ }
+
+ // clean up phase did not resume at the frame that the search phase said it would
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+static _Unwind_Reason_Code unwind_phase2_forced(unw_context_t* uc, struct _Unwind_Exception* exception_object,
+ _Unwind_Stop_Fn stop, void* stop_parameter)
+{
+ unw_cursor_t cursor2;
+ unw_init_local(&cursor2, uc);
+
+ // walk each frame until we reach where search phase said to stop
+ while ( unw_step(&cursor2) > 0 ) {
+
+ // get info about this frame
+ unw_proc_info_t frameInfo;
+ if ( unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step failed => _URC_END_OF_STACK\n", exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+
+ // debugging
+ if ( DEBUG_PRINT_UNWINDING_TEST ) {
+ char functionName[512];
+ unw_word_t offset;
+ if ( (unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
+ strcpy(functionName, ".anonymous.");
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): start_ip=0x%llX, func=%s, lsda=0x%llX, personality=0x%llX\n",
+ exception_object, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler);
+ }
+
+ // call stop function at each frame
+ _Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE);
+ _Unwind_Reason_Code stopResult = (*stop)(1, action,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)(&cursor2), stop_parameter);
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", exception_object, stopResult);
+ if ( stopResult != _URC_NO_REASON ) {
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // if there is a personality routine, tell it we are unwinding
+ if ( frameInfo.handler != 0 ) {
+ __personality_routine p = (__personality_routine)(long)(frameInfo.handler);
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", exception_object, p);
+ _Unwind_Reason_Code personalityResult = (*p)(1, action,
+ exception_object->exception_class, exception_object,
+ (struct _Unwind_Context*)(&cursor2));
+ switch ( personalityResult ) {
+ case _URC_CONTINUE_UNWIND:
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_CONTINUE_UNWIND\n", exception_object);
+ // destructors called, continue unwinding
+ break;
+ case _URC_INSTALL_CONTEXT:
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_INSTALL_CONTEXT\n", exception_object);
+ // we may get control back if landing pad calls _Unwind_Resume()
+ unw_resume(&cursor2);
+ break;
+ default:
+ // something went wrong
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned %d, _URC_FATAL_PHASE2_ERROR\n",
+ exception_object, personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ }
+
+ // call stop function one last time and tell it we've reached the end of the stack
+ DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop function with _UA_END_OF_STACK\n", exception_object);
+ _Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE|_UA_END_OF_STACK);
+ (*stop)(1, lastAction, exception_object->exception_class, exception_object, (struct _Unwind_Context*)(&cursor2), stop_parameter);
+
+ // clean up phase did not resume at the frame that the search phase said it would
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+//
+// Called by __cxa_throw. Only returns if there is a fatal error
+//
+EXPORT _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_RaiseException(ex_obj=%p)\n", exception_object);
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right thing
+ exception_object->private_1 = 0;
+ exception_object->private_2 = 0;
+
+ // phase 1: the search phase
+ _Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object);
+ if ( phase1 != _URC_NO_REASON )
+ return phase1;
+
+ // phase 2: the clean up phase
+ return unwind_phase2(&uc, exception_object);
+}
+
+
+//
+// When _Unwind_RaiseException() is in phase2, it hands control
+// to the personality function at each frame. The personality
+// may force a jump to a landing pad in that function, the landing
+// pad code may then call _Unwind_Resume() to continue with the
+// unwinding. Note: the call to _Unwind_Resume() is from compiler
+// geneated user code. All other _Unwind_* routines are called
+// by the C++ runtime __cxa_* routines.
+//
+// Re-throwing an exception is implemented by having the code call
+// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
+//
+EXPORT void _Unwind_Resume(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_Resume(ex_obj=%p)\n", exception_object);
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ if ( exception_object->private_1 != 0 )
+ unwind_phase2_forced(&uc, exception_object, (_Unwind_Stop_Fn)exception_object->private_1, (void*)exception_object->private_2);
+ else
+ unwind_phase2(&uc, exception_object);
+
+ // clients assume _Unwind_Resume() does not return, so all we can do is abort.
+ ABORT("_Unwind_Resume() can't return");
+}
+
+
+
+//
+// Not used by C++.
+// Unwinds stack, calling "stop" function at each frame
+// Could be used to implement longjmp().
+//
+EXPORT _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter)
+{
+ DEBUG_PRINT_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)\n", exception_object, stop);
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ // mark that this is a forced unwind, so _Unwind_Resume() can do the right thing
+ exception_object->private_1 = (uintptr_t)stop;
+ exception_object->private_2 = (uintptr_t)stop_parameter;
+
+ // doit
+ return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter);
+}
+
+
+//
+// Called by personality handler during phase 2 to get LSDA for current frame
+//
+EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context)
+{
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_proc_info_t frameInfo;
+ uintptr_t result = 0;
+ if ( unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS )
+ result = frameInfo.lsda;
+ DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%lX\n", context, result);
+ if ( result != 0 ) {
+ if ( *((uint8_t*)result) != 0xFF )
+ DEBUG_MESSAGE("lsda at 0x%lX does not start with 0xFF\n", result);
+ }
+ return result;
+}
+
+
+//
+// Called by personality handler during phase 2 to get register values
+//
+EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index)
+{
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_word_t result;
+ unw_get_reg(cursor, index, &result);
+ DEBUG_PRINT_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%llX\n", context, index, (uint64_t)result);
+ return result;
+}
+
+
+//
+// Called by personality handler during phase 2 to alter register values
+//
+EXPORT void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value)
+{
+ DEBUG_PRINT_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0llX)\n", context, index, (uint64_t)new_value);
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_set_reg(cursor, index, new_value);
+}
+
+
+//
+// Called by personality handler during phase 2 to get instruction pointer
+//
+EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context* context)
+{
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_word_t result;
+ unw_get_reg(cursor, UNW_REG_IP, &result);
+ DEBUG_PRINT_API("_Unwind_GetIP(context=%p) => 0x%llX\n", context, (uint64_t)result);
+ return result;
+}
+
+
+//
+// Called by personality handler during phase 2 to alter instruction pointer
+//
+EXPORT void _Unwind_SetIP(struct _Unwind_Context* context, uintptr_t new_value)
+{
+ DEBUG_PRINT_API("_Unwind_SetIP(context=%p, value=0x%0llX)\n", context, (uint64_t)new_value);
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_set_reg(cursor, UNW_REG_IP, new_value);
+}
+
+
+//
+// Called by personality handler during phase 2 to find the start of the function
+//
+EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context)
+{
+ unw_cursor_t* cursor = (unw_cursor_t*)context;
+ unw_proc_info_t frameInfo;
+ uintptr_t result = 0;
+ if ( unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS )
+ result = frameInfo.start_ip;
+ DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p) => 0x%lX\n", context, result);
+ return result;
+}
+
+
+//
+// Called by personality handler during phase 2 if a foreign exception is caught
+//
+EXPORT void _Unwind_DeleteException(struct _Unwind_Exception* exception_object)
+{
+ DEBUG_PRINT_API("_Unwind_DeleteException(ex_obj=%p)\n", exception_object);
+ if ( exception_object->exception_cleanup != NULL )
+ (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object);
+}
+
+
+
+
+//
+// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in earlier versions
+//
+NOT_HERE_BEFORE_10_6(_Unwind_DeleteException)
+NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE)
+NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind)
+NOT_HERE_BEFORE_10_6(_Unwind_GetGR)
+NOT_HERE_BEFORE_10_6(_Unwind_GetIP)
+NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData)
+NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart)
+NOT_HERE_BEFORE_10_6(_Unwind_RaiseException)
+NOT_HERE_BEFORE_10_6(_Unwind_Resume)
+NOT_HERE_BEFORE_10_6(_Unwind_SetGR)
+NOT_HERE_BEFORE_10_6(_Unwind_SetIP)
+
+#endif // __ppc__ || __i386__ || __x86_64__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/dwarf2.h b/lldb/source/Plugins/Process/Utility/libunwind/src/dwarf2.h
new file mode 100644
index 00000000000..83414332c5e
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/dwarf2.h
@@ -0,0 +1,245 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- dwarf2.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/* These constants were taken from version 3 of the DWARF standard,
+ which is Copyright (c) 2005 Free Standards Group, and
+ Copyright (c) 1992, 1993 UNIX International, Inc.
+*/
+
+
+#ifndef __DWARF2__
+#define __DWARF2__
+
+namespace lldb_private {
+
+// dwarf unwind instructions
+enum {
+ DW_CFA_nop = 0x0,
+ DW_CFA_set_loc = 0x1,
+ DW_CFA_advance_loc1 = 0x2,
+ DW_CFA_advance_loc2 = 0x3,
+ DW_CFA_advance_loc4 = 0x4,
+ DW_CFA_offset_extended = 0x5,
+ DW_CFA_restore_extended = 0x6,
+ DW_CFA_undefined = 0x7,
+ DW_CFA_same_value = 0x8,
+ DW_CFA_register = 0x9,
+ DW_CFA_remember_state = 0xA,
+ DW_CFA_restore_state = 0xB,
+ DW_CFA_def_cfa = 0xC,
+ DW_CFA_def_cfa_register = 0xD,
+ DW_CFA_def_cfa_offset = 0xE,
+ DW_CFA_def_cfa_expression = 0xF,
+ DW_CFA_expression = 0x10,
+ DW_CFA_offset_extended_sf = 0x11,
+ DW_CFA_def_cfa_sf = 0x12,
+ DW_CFA_def_cfa_offset_sf = 0x13,
+ DW_CFA_val_offset = 0x14,
+ DW_CFA_val_offset_sf = 0x15,
+ DW_CFA_val_expression = 0x16,
+ DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
+ DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register
+ DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
+
+ // GNU extensions
+ DW_CFA_GNU_window_save = 0x2D,
+ DW_CFA_GNU_args_size = 0x2E,
+ DW_CFA_GNU_negative_offset_extended = 0x2F
+};
+
+
+// FSF exception handling Pointer-Encoding constants
+// Used in CFI augmentation by gcc compiler
+enum {
+ DW_EH_PE_ptr = 0x00,
+ DW_EH_PE_uleb128 = 0x01,
+ DW_EH_PE_udata2 = 0x02,
+ DW_EH_PE_udata4 = 0x03,
+ DW_EH_PE_udata8 = 0x04,
+ DW_EH_PE_signed = 0x08,
+ DW_EH_PE_sleb128 = 0x09,
+ DW_EH_PE_sdata2 = 0x0A,
+ DW_EH_PE_sdata4 = 0x0B,
+ DW_EH_PE_sdata8 = 0x0C,
+ DW_EH_PE_absptr = 0x00,
+ DW_EH_PE_pcrel = 0x10,
+ DW_EH_PE_textrel = 0x20,
+ DW_EH_PE_datarel = 0x30,
+ DW_EH_PE_funcrel = 0x40,
+ DW_EH_PE_aligned = 0x50,
+ DW_EH_PE_indirect = 0x80,
+ DW_EH_PE_omit = 0xFF
+};
+
+
+// DWARF expressions
+enum {
+ DW_OP_addr = 0x03, // constant address (size target specific)
+ DW_OP_deref = 0x06,
+ DW_OP_const1u = 0x08, // 1-byte constant
+ DW_OP_const1s = 0x09, // 1-byte constant
+ DW_OP_const2u = 0x0A, // 2-byte constant
+ DW_OP_const2s = 0x0B, // 2-byte constant
+ DW_OP_const4u = 0x0C, // 4-byte constant
+ DW_OP_const4s = 0x0D, // 4-byte constant
+ DW_OP_const8u = 0x0E, // 8-byte constant
+ DW_OP_const8s = 0x0F, // 8-byte constant
+ DW_OP_constu = 0x10, // ULEB128 constant
+ DW_OP_consts = 0x11, // SLEB128 constant
+ DW_OP_dup = 0x12,
+ DW_OP_drop = 0x13,
+ DW_OP_over = 0x14,
+ DW_OP_pick = 0x15, // 1-byte stack index
+ DW_OP_swap = 0x16,
+ DW_OP_rot = 0x17,
+ DW_OP_xderef = 0x18,
+ DW_OP_abs = 0x19,
+ DW_OP_and = 0x1A,
+ DW_OP_div = 0x1B,
+ DW_OP_minus = 0x1C,
+ DW_OP_mod = 0x1D,
+ DW_OP_mul = 0x1E,
+ DW_OP_neg = 0x1F,
+ DW_OP_not = 0x20,
+ DW_OP_or = 0x21,
+ DW_OP_plus = 0x22,
+ DW_OP_plus_uconst = 0x23, // ULEB128 addend
+ DW_OP_shl = 0x24,
+ DW_OP_shr = 0x25,
+ DW_OP_shra = 0x26,
+ DW_OP_xor = 0x27,
+ DW_OP_skip = 0x2F, // signed 2-byte constant
+ DW_OP_bra = 0x28, // signed 2-byte constant
+ DW_OP_eq = 0x29,
+ DW_OP_ge = 0x2A,
+ DW_OP_gt = 0x2B,
+ DW_OP_le = 0x2C,
+ DW_OP_lt = 0x2D,
+ DW_OP_ne = 0x2E,
+ DW_OP_lit0 = 0x30, // Literal 0
+ DW_OP_lit1 = 0x31, // Literal 1
+ DW_OP_lit2 = 0x32, // Literal 2
+ DW_OP_lit3 = 0x33, // Literal 3
+ DW_OP_lit4 = 0x34, // Literal 4
+ DW_OP_lit5 = 0x35, // Literal 5
+ DW_OP_lit6 = 0x36, // Literal 6
+ DW_OP_lit7 = 0x37, // Literal 7
+ DW_OP_lit8 = 0x38, // Literal 8
+ DW_OP_lit9 = 0x39, // Literal 9
+ DW_OP_lit10 = 0x3A, // Literal 10
+ DW_OP_lit11 = 0x3B, // Literal 11
+ DW_OP_lit12 = 0x3C, // Literal 12
+ DW_OP_lit13 = 0x3D, // Literal 13
+ DW_OP_lit14 = 0x3E, // Literal 14
+ DW_OP_lit15 = 0x3F, // Literal 15
+ DW_OP_lit16 = 0x40, // Literal 16
+ DW_OP_lit17 = 0x41, // Literal 17
+ DW_OP_lit18 = 0x42, // Literal 18
+ DW_OP_lit19 = 0x43, // Literal 19
+ DW_OP_lit20 = 0x44, // Literal 20
+ DW_OP_lit21 = 0x45, // Literal 21
+ DW_OP_lit22 = 0x46, // Literal 22
+ DW_OP_lit23 = 0x47, // Literal 23
+ DW_OP_lit24 = 0x48, // Literal 24
+ DW_OP_lit25 = 0x49, // Literal 25
+ DW_OP_lit26 = 0x4A, // Literal 26
+ DW_OP_lit27 = 0x4B, // Literal 27
+ DW_OP_lit28 = 0x4C, // Literal 28
+ DW_OP_lit29 = 0x4D, // Literal 29
+ DW_OP_lit30 = 0x4E, // Literal 30
+ DW_OP_lit31 = 0x4F, // Literal 31
+ DW_OP_reg0 = 0x50, // Contents of reg0
+ DW_OP_reg1 = 0x51, // Contents of reg1
+ DW_OP_reg2 = 0x52, // Contents of reg2
+ DW_OP_reg3 = 0x53, // Contents of reg3
+ DW_OP_reg4 = 0x54, // Contents of reg4
+ DW_OP_reg5 = 0x55, // Contents of reg5
+ DW_OP_reg6 = 0x56, // Contents of reg6
+ DW_OP_reg7 = 0x57, // Contents of reg7
+ DW_OP_reg8 = 0x58, // Contents of reg8
+ DW_OP_reg9 = 0x59, // Contents of reg9
+ DW_OP_reg10 = 0x5A, // Contents of reg10
+ DW_OP_reg11 = 0x5B, // Contents of reg11
+ DW_OP_reg12 = 0x5C, // Contents of reg12
+ DW_OP_reg13 = 0x5D, // Contents of reg13
+ DW_OP_reg14 = 0x5E, // Contents of reg14
+ DW_OP_reg15 = 0x5F, // Contents of reg15
+ DW_OP_reg16 = 0x60, // Contents of reg16
+ DW_OP_reg17 = 0x61, // Contents of reg17
+ DW_OP_reg18 = 0x62, // Contents of reg18
+ DW_OP_reg19 = 0x63, // Contents of reg19
+ DW_OP_reg20 = 0x64, // Contents of reg20
+ DW_OP_reg21 = 0x65, // Contents of reg21
+ DW_OP_reg22 = 0x66, // Contents of reg22
+ DW_OP_reg23 = 0x67, // Contents of reg23
+ DW_OP_reg24 = 0x68, // Contents of reg24
+ DW_OP_reg25 = 0x69, // Contents of reg25
+ DW_OP_reg26 = 0x6A, // Contents of reg26
+ DW_OP_reg27 = 0x6B, // Contents of reg27
+ DW_OP_reg28 = 0x6C, // Contents of reg28
+ DW_OP_reg29 = 0x6D, // Contents of reg29
+ DW_OP_reg30 = 0x6E, // Contents of reg30
+ DW_OP_reg31 = 0x6F, // Contents of reg31
+ DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset
+ DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset
+ DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset
+ DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset
+ DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset
+ DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset
+ DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset
+ DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset
+ DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset
+ DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset
+ DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset
+ DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset
+ DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset
+ DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset
+ DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset
+ DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset
+ DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset
+ DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset
+ DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset
+ DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset
+ DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset
+ DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset
+ DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset
+ DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset
+ DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset
+ DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset
+ DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset
+ DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset
+ DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset
+ DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset
+ DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset
+ DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset
+ DW_OP_regx = 0x90, // ULEB128 register
+ DW_OP_fbreg = 0x91, // SLEB128 offset
+ DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset
+ DW_OP_piece = 0x93, // ULEB128 size of piece addressed
+ DW_OP_deref_size = 0x94, // 1-byte size of data retrieved
+ DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved
+ DW_OP_nop = 0x96,
+ DW_OP_push_object_addres = 0x97,
+ DW_OP_call2 = 0x98, // 2-byte offset of DIE
+ DW_OP_call4 = 0x99, // 4-byte offset of DIE
+ DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE
+ DW_OP_lo_user = 0xE0,
+ DW_OP_APPLE_uninit = 0xF0,
+ DW_OP_hi_user = 0xFF
+};
+
+
+}; // namespace lldb_private
+
+
+#endif
+
+
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/libunwind_priv.h b/lldb/source/Plugins/Process/Utility/libunwind/src/libunwind_priv.h
new file mode 100644
index 00000000000..fe25780c538
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/libunwind_priv.h
@@ -0,0 +1,35 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- libunwind_priv.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __LIBUNWIND_PRIV__
+#define __LIBUNWIND_PRIV__
+
+namespace lldb_private {
+#include "libunwind.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ // SPI
+ extern void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));
+
+ // IPI
+ extern void _unw_add_dynamic_fde(unw_word_t fde);
+ extern void _unw_remove_dynamic_fde(unw_word_t fde);
+
+#ifdef __cplusplus
+}
+#endif
+
+}; // namespace lldb_private
+
+
+#endif
+
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/libuwind.cxx b/lldb/source/Plugins/Process/Utility/libunwind/src/libuwind.cxx
new file mode 100644
index 00000000000..e7e66a452f0
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/libuwind.cxx
@@ -0,0 +1,421 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- libuwind.cxx --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if __ppc__ || __i386__ || __x86_64__
+
+#include <mach/mach_types.h>
+#include <mach/machine.h>
+#include <new>
+
+#include "libunwind.h"
+#include "libunwind_priv.h"
+
+#include "UnwindCursor.hpp"
+#include "AddressSpace.hpp"
+
+#include "RemoteProcInfo.hpp"
+
+namespace lldb_private {
+
+// setup debug logging hooks
+INITIALIZE_DEBUG_PRINT_API
+INITIALIZE_DEBUG_PRINT_UNWINDING
+
+// internal object to represent this processes address space
+static LocalAddressSpace sThisAddressSpace;
+
+#pragma mark Local API
+
+///
+/// record the registers and stack position of the caller
+///
+extern int unw_getcontext(unw_context_t*);
+// note: unw_getcontext() implemented in assembly
+
+///
+/// create a cursor of a thread in this process given 'context' recorded by unw_getcontext()
+///
+EXPORT int unw_init_local(unw_cursor_t* cursor, unw_context_t* context)
+{
+ DEBUG_PRINT_API("unw_init_local(cursor=%p, context=%p)\n", cursor, context);
+ // use "placement new" to allocate UnwindCursor in the cursor buffer
+#if __i386__
+ new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_x86>(context, sThisAddressSpace);
+#elif __x86_64__
+ new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_x86_64>(context, sThisAddressSpace);
+#elif __ppc__
+ new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_ppc>(context, sThisAddressSpace);
+#endif
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ co->setInfoBasedOnIPRegister(NULL);
+
+ return UNW_ESUCCESS;
+}
+
+///
+/// move cursor to next frame
+///
+EXPORT int unw_step(unw_cursor_t* cursor)
+{
+ DEBUG_PRINT_API("unw_step(cursor=%p)\n", cursor);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ return co->step();
+}
+
+///
+/// get value of specified register at cursor position in stack frame
+///
+EXPORT int unw_get_reg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_word_t* value)
+{
+ DEBUG_PRINT_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n", cursor, regNum, value);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+
+ if (co->validReg(regNum) == 0)
+ return UNW_EBADREG;
+ return co->getReg(regNum, value);
+}
+
+///
+/// get value of specified float register at cursor position in stack frame
+///
+EXPORT int unw_get_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_fpreg_t* value)
+{
+ DEBUG_PRINT_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n", cursor, regNum, value);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+
+ if ( co->validFloatReg(regNum) ) {
+ return co->getFloatReg(regNum, value);
+ }
+ return UNW_EBADREG;
+}
+
+///
+/// set value of specified register at cursor position in stack frame
+///
+EXPORT int unw_set_reg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_word_t value)
+{
+ DEBUG_PRINT_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n", cursor, regNum, value);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+
+ if ( co->validReg(regNum) ) {
+ co->setReg(regNum, value);
+ // specical case altering IP to re-find info (being called by personality function)
+ if ( regNum == UNW_REG_IP ) {
+ unw_proc_info_t info;
+ co->getInfo(&info);
+ uint64_t orgArgSize = info.gp;
+ uint64_t orgFuncStart = info.start_ip;
+ co->setInfoBasedOnIPRegister(false);
+ // and adjust REG_SP if there was a DW_CFA_GNU_args_size
+ if ( (orgFuncStart == info.start_ip) && (orgArgSize != 0) )
+ co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + orgArgSize);
+ }
+ return UNW_ESUCCESS;
+ }
+ return UNW_EBADREG;
+}
+
+///
+/// set value of specified float register at cursor position in stack frame
+///
+EXPORT int unw_set_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_fpreg_t value)
+{
+ DEBUG_PRINT_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n", cursor, regNum, value);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+
+ if ( co->validFloatReg(regNum) ) {
+ return co->setFloatReg(regNum, value);
+ }
+ return UNW_EBADREG;
+}
+
+///
+/// resume execution at cursor position (aka longjump)
+///
+EXPORT int unw_resume(unw_cursor_t* cursor)
+{
+ DEBUG_PRINT_API("unw_resume(cursor=%p)\n", cursor);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+
+ co->jumpto();
+ return UNW_EUNSPEC;
+}
+
+///
+/// returns the name of a register
+///
+EXPORT const char* unw_regname(unw_cursor_t* cursor, unw_regnum_t regNum)
+{
+ DEBUG_PRINT_API("unw_regname(cursor=%p, regNum=%d)\n", cursor, regNum);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ return co->getRegisterName(regNum);
+}
+
+///
+/// get unwind info at cursor position in stack frame
+///
+EXPORT int unw_get_proc_info(unw_cursor_t* cursor, unw_proc_info_t* info)
+{
+ DEBUG_PRINT_API("unw_get_proc_info(cursor=%p, &info=%p)\n", cursor, info);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ co->getInfo(info);
+ if ( info->end_ip == 0 )
+ return UNW_ENOINFO;
+ else
+ return UNW_ESUCCESS;
+}
+
+///
+/// checks if a register is a floating-point register
+///
+EXPORT int unw_is_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum)
+{
+ DEBUG_PRINT_API("unw_is_fpreg(cursor=%p, regNum=%d)\n", cursor, regNum);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ return co->validFloatReg(regNum);
+}
+
+///
+/// checks if current frame is signal trampoline
+///
+EXPORT int unw_is_signal_frame(unw_cursor_t* cursor)
+{
+ DEBUG_PRINT_API("unw_is_signal_frame(cursor=%p)\n", cursor);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ return co->isSignalFrame();
+}
+
+///
+/// get name of function at cursor position in stack frame
+///
+EXPORT int unw_get_proc_name(unw_cursor_t* cursor, char* buf, size_t bufLen, unw_word_t* offset)
+{
+ DEBUG_PRINT_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%ld)\n", cursor, buf, bufLen);
+ AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
+ if ( co->getFunctionName(buf, bufLen, offset) )
+ return UNW_ESUCCESS;
+ else
+ return UNW_EUNSPEC;
+}
+
+#pragma mark Remote API
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+EXPORT int unw_init_remote(unw_cursor_t *cursor, unw_addr_space_t as, void *arg)
+{
+ DEBUG_PRINT_API("init_remote(c=%p, as=%p, arg=%p)\n", cursor, as, arg);
+
+ // API docs at http://www.nongnu.org/libunwind/docs.html say we should
+ // handle a local address space but we're not doing the "remote" unwinding
+ // with local process accessors so punt on that.
+
+ if(as->type != UNW_REMOTE)
+ {
+ ABORT("unw_init_remote was passed a non-remote address space");
+ return UNW_EINVAL;
+ }
+
+ unw_accessors_t* acc = unw_get_accessors(as);
+ if(!acc) {
+ ABORT("unw_get_accessors returned NULL");
+ return UNW_EINVAL;
+ }
+
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)as;
+
+ // use "placement new" to allocate UnwindCursor in the cursor buffer
+ // It isn't really necessary to use placement new in the remote API but we'll stay consistent
+ // with the rest of the code here.
+ switch ( remote->ras->getTargetArch() ) {
+ case UNW_TARGET_I386:
+ {
+ Registers_x86 *r = new Registers_x86;
+ OtherAddressSpace<Pointer32<LittleEndian> > *addrSpace = new OtherAddressSpace<Pointer32<LittleEndian> >(as, arg);
+ getRemoteContext (remote->ras, *r, arg);
+ unw_context_t *context = (unw_context_t*) r;
+ new ((void*)cursor) RemoteUnwindCursor<OtherAddressSpace<Pointer32<LittleEndian> >, Registers_x86>(*addrSpace, context, arg);
+ break;
+ }
+ break;
+ case UNW_TARGET_X86_64:
+ {
+ Registers_x86_64 *r = new Registers_x86_64;
+ OtherAddressSpace<Pointer64<LittleEndian> > *addrSpace = new OtherAddressSpace<Pointer64<LittleEndian> >(as, arg);
+ getRemoteContext (remote->ras, *r, arg);
+ unw_context_t *context = (unw_context_t*) r;
+ new ((void*)cursor) RemoteUnwindCursor<OtherAddressSpace<Pointer64<LittleEndian> >, Registers_x86_64>(*addrSpace, context, arg);
+ break;
+ }
+
+ case UNW_TARGET_PPC:
+ ABORT("ppc not supported for remote unwinds");
+ break;
+
+ case UNW_TARGET_ARM:
+ ABORT("arm not supported for remote unwinds");
+ break;
+
+ default:
+ return UNW_EUNSPEC;
+ }
+
+ AbstractRemoteUnwindCursor* co = (AbstractRemoteUnwindCursor*)cursor;
+ co->setRemoteContext(arg);
+
+ return UNW_ESUCCESS;
+}
+
+// The documentation disagrees about whether or not this returns a pointer. Now it does.
+EXPORT unw_accessors_t* unw_get_accessors(unw_addr_space_t as)
+{
+ if(as->type != UNW_REMOTE)
+ {
+ ABORT("unw_get_accessors was passed a non-remote address space");
+ return NULL;
+ }
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)as;
+
+ if(remote->type != UNW_REMOTE)
+ return NULL;
+
+ return remote->ras->getAccessors();
+}
+
+EXPORT unw_addr_space_t unw_create_addr_space(unw_accessors_t *ap, unw_targettype_t targarch)
+{
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)malloc(sizeof(unw_addr_space_remote));
+ remote->type = UNW_REMOTE;
+ remote->ras = new RemoteProcInfo(ap, targarch);
+ return (unw_addr_space_t)remote;
+}
+
+EXPORT void unw_flush_caches(unw_addr_space_t as)
+{
+ if(as->type != UNW_REMOTE)
+ {
+ ABORT("unw_flush_caches was passed a non-remote address space");
+ return;
+ }
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)as;
+ remote->ras->flushAllCaches();
+
+ return;
+}
+
+EXPORT void unw_image_was_unloaded (unw_addr_space_t as, unw_word_t mh)
+{
+ if(as->type != UNW_REMOTE)
+ {
+ ABORT("unw_image_was_unloaded was passed a non-remote address space");
+ return;
+ }
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)as;
+ remote->ras->flushCacheByMachHeader(mh);
+
+ return;
+}
+
+
+EXPORT int unw_set_caching_policy(unw_addr_space_t as, unw_caching_policy_t policy)
+{
+ if(as->type != UNW_REMOTE)
+ {
+ ABORT("unw_set_caching_policy was passed a non-remote address space");
+ return UNW_EINVAL;
+ }
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)as;
+ return remote->ras->setCachingPolicy(policy);
+}
+
+EXPORT unw_addr_space_t unw_local_addr_space = (unw_addr_space_t)&sThisAddressSpace;
+
+///
+/// delete an address_space object
+///
+EXPORT void unw_destroy_addr_space(unw_addr_space_t asp)
+{
+ if(asp->type != UNW_REMOTE) {
+ ABORT("unw_destroy_addr_space was passed a non-remote address space");
+ return;
+ }
+
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)asp;
+ delete remote->ras;
+}
+
+EXPORT void unw_set_logging_level(unw_addr_space_t as, FILE *f, unw_log_level_t level)
+{
+ if (as->type != UNW_REMOTE) {
+ ABORT("unw_set_logging_level was passed a non-remote address space");
+ return;
+ }
+
+ unw_addr_space_remote* remote = (unw_addr_space_remote*)as;
+ return remote->ras->setLoggingLevel(f, level);
+}
+
+
+EXPORT int unw_end_of_prologue_setup(unw_cursor_t* cursor, unw_word_t start, unw_word_t end, unw_word_t *endofprologue)
+{
+ AbstractRemoteUnwindCursor* co = (AbstractRemoteUnwindCursor*)cursor;
+ if (!co->remoteUnwindCursor())
+ ABORT("unw_end_of_prologue_setup called with a non-remote unwind cursor.");
+
+ return co->endOfPrologueInsns (start, end, endofprologue);
+}
+
+
+#endif // SUPPORT_REMOTE_UNWINDING
+
+#pragma mark Dynamic unwinding API
+
+#if !FOR_DYLD
+///
+/// SPI: walks cached dwarf entries
+///
+EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh))
+{
+ DEBUG_PRINT_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", func);
+ DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
+}
+#endif // !FOR_DYLD
+
+#if !FOR_DYLD
+//
+// IPI: for __register_frame()
+//
+void _unw_add_dynamic_fde(unw_word_t fde)
+{
+ CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+ CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+ const char* message = CFI_Parser<LocalAddressSpace>::decodeFDE(sThisAddressSpace, (LocalAddressSpace::pint_t)fde, & fdeInfo, &cieInfo);
+ if ( message == NULL ) {
+ // dynamically registered FDEs don't have a mach_header group they are in. Use fde as mh_group
+ unw_word_t mh_group = fdeInfo.fdeStart;
+ DwarfFDECache<LocalAddressSpace>::add(mh_group, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart);
+ }
+ else {
+ DEBUG_MESSAGE("_unw_add_dynamic_fde: bad fde: %s", message);
+ }
+}
+
+//
+// IPI: for __deregister_frame()
+//
+void _unw_remove_dynamic_fde(unw_word_t fde)
+{
+ // fde is own mh_group
+ DwarfFDECache<LocalAddressSpace>::removeAllIn(fde);
+}
+#endif
+
+}; // namespace lldb_private
+
+#endif // __ppc__ || __i386__ || __x86_64__
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/unw_getcontext.s b/lldb/source/Plugins/Process/Utility/libunwind/src/unw_getcontext.s
new file mode 100644
index 00000000000..8d3a451fd92
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/unw_getcontext.s
@@ -0,0 +1,229 @@
+
+#if __i386__ || __x86_64__ || __ppc__
+
+ .text
+ .globl _unw_getcontext
+_unw_getcontext:
+
+#endif // __i386__ || __x86_64__ || __ppc__
+
+
+#if __i386__
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# + +
+# +-----------------------+
+# + thread_state pointer +
+# +-----------------------+
+# + return address +
+# +-----------------------+ <-- SP
+# + +
+#
+ push %eax
+ movl 8(%esp), %eax
+ movl %ebx, 4(%eax)
+ movl %ecx, 8(%eax)
+ movl %edx, 12(%eax)
+ movl %edi, 16(%eax)
+ movl %esi, 20(%eax)
+ movl %ebp, 24(%eax)
+ movl %esp, %edx
+ addl $8, %edx
+ movl %edx, 28(%eax) # store what sp was at call site as esp
+ # skip ss
+ # skip eflags
+ movl 4(%esp), %edx
+ movl %edx, 40(%eax) # store return address as eip
+ # skip cs
+ # skip ds
+ # skip es
+ # skip fs
+ # skip gs
+ movl (%esp), %edx
+ movl %edx, (%eax) # store original eax
+ popl %eax
+ xorl %eax, %eax # return UNW_ESUCCESS
+ ret
+
+#elif __x86_64__
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# thread_state pointer is in rdi
+#
+ movq %rax, (%rdi)
+ movq %rbx, 8(%rdi)
+ movq %rcx, 16(%rdi)
+ movq %rdx, 24(%rdi)
+ movq %rdi, 32(%rdi)
+ movq %rsi, 40(%rdi)
+ movq %rbp, 48(%rdi)
+ movq %rsp, 56(%rdi)
+ addq $8, 56(%rdi)
+ movq %r8, 64(%rdi)
+ movq %r9, 72(%rdi)
+ movq %r10, 80(%rdi)
+ movq %r11, 88(%rdi)
+ movq %r12, 96(%rdi)
+ movq %r13,104(%rdi)
+ movq %r14,112(%rdi)
+ movq %r15,120(%rdi)
+ movq (%rsp),%rsi
+ movq %rsi,128(%rdi) # store return address as rip
+ # skip rflags
+ # skip cs
+ # skip fs
+ # skip gs
+ xorl %eax, %eax # return UNW_ESUCCESS
+ ret
+
+#elif __ppc__
+
+;
+; extern int unw_getcontext(unw_context_t* thread_state)
+;
+; On entry:
+; thread_state pointer is in r3
+;
+ stw r0, 8(r3)
+ mflr r0
+ stw r0, 0(r3) ; store lr as ssr0
+ stw r1, 12(r3)
+ stw r2, 16(r3)
+ stw r3, 20(r3)
+ stw r4, 24(r3)
+ stw r5, 28(r3)
+ stw r6, 32(r3)
+ stw r7, 36(r3)
+ stw r8, 40(r3)
+ stw r9, 44(r3)
+ stw r10, 48(r3)
+ stw r11, 52(r3)
+ stw r12, 56(r3)
+ stw r13, 60(r3)
+ stw r14, 64(r3)
+ stw r15, 68(r3)
+ stw r16, 72(r3)
+ stw r17, 76(r3)
+ stw r18, 80(r3)
+ stw r19, 84(r3)
+ stw r20, 88(r3)
+ stw r21, 92(r3)
+ stw r22, 96(r3)
+ stw r23,100(r3)
+ stw r24,104(r3)
+ stw r25,108(r3)
+ stw r26,112(r3)
+ stw r27,116(r3)
+ stw r28,120(r3)
+ stw r29,124(r3)
+ stw r30,128(r3)
+ stw r31,132(r3)
+
+ ; save VRSave register
+ mfspr r0,256
+ stw r0,156(r3)
+ ; save CR registers
+ mfcr r0
+ stw r0,136(r3)
+ ; save CTR register
+ mfctr r0
+ stw r0,148(r3)
+
+ ; save float registers
+ stfd f0, 160(r3)
+ stfd f1, 168(r3)
+ stfd f2, 176(r3)
+ stfd f3, 184(r3)
+ stfd f4, 192(r3)
+ stfd f5, 200(r3)
+ stfd f6, 208(r3)
+ stfd f7, 216(r3)
+ stfd f8, 224(r3)
+ stfd f9, 232(r3)
+ stfd f10,240(r3)
+ stfd f11,248(r3)
+ stfd f12,256(r3)
+ stfd f13,264(r3)
+ stfd f14,272(r3)
+ stfd f15,280(r3)
+ stfd f16,288(r3)
+ stfd f17,296(r3)
+ stfd f18,304(r3)
+ stfd f19,312(r3)
+ stfd f20,320(r3)
+ stfd f21,328(r3)
+ stfd f22,336(r3)
+ stfd f23,344(r3)
+ stfd f24,352(r3)
+ stfd f25,360(r3)
+ stfd f26,368(r3)
+ stfd f27,376(r3)
+ stfd f28,384(r3)
+ stfd f29,392(r3)
+ stfd f30,400(r3)
+ stfd f31,408(r3)
+
+
+ ; save vector registers
+
+ subi r4,r1,16
+ rlwinm r4,r4,0,0,27 ; mask low 4-bits
+ ; r4 is now a 16-byte aligned pointer into the red zone
+
+#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \
+ stvx _vec,0,r4 @\
+ lwz r5, 0(r4) @\
+ stw r5, _offset(r3) @\
+ lwz r5, 4(r4) @\
+ stw r5, _offset+4(r3) @\
+ lwz r5, 8(r4) @\
+ stw r5, _offset+8(r3) @\
+ lwz r5, 12(r4) @\
+ stw r5, _offset+12(r3)
+
+ SAVE_VECTOR_UNALIGNED( v0, 424+0x000)
+ SAVE_VECTOR_UNALIGNED( v1, 424+0x010)
+ SAVE_VECTOR_UNALIGNED( v2, 424+0x020)
+ SAVE_VECTOR_UNALIGNED( v3, 424+0x030)
+ SAVE_VECTOR_UNALIGNED( v4, 424+0x040)
+ SAVE_VECTOR_UNALIGNED( v5, 424+0x050)
+ SAVE_VECTOR_UNALIGNED( v6, 424+0x060)
+ SAVE_VECTOR_UNALIGNED( v7, 424+0x070)
+ SAVE_VECTOR_UNALIGNED( v8, 424+0x080)
+ SAVE_VECTOR_UNALIGNED( v9, 424+0x090)
+ SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0)
+ SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0)
+ SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0)
+ SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0)
+ SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0)
+ SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0)
+ SAVE_VECTOR_UNALIGNED(v16, 424+0x100)
+ SAVE_VECTOR_UNALIGNED(v17, 424+0x110)
+ SAVE_VECTOR_UNALIGNED(v18, 424+0x120)
+ SAVE_VECTOR_UNALIGNED(v19, 424+0x130)
+ SAVE_VECTOR_UNALIGNED(v20, 424+0x140)
+ SAVE_VECTOR_UNALIGNED(v21, 424+0x150)
+ SAVE_VECTOR_UNALIGNED(v22, 424+0x160)
+ SAVE_VECTOR_UNALIGNED(v23, 424+0x170)
+ SAVE_VECTOR_UNALIGNED(v24, 424+0x180)
+ SAVE_VECTOR_UNALIGNED(v25, 424+0x190)
+ SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0)
+ SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0)
+ SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0)
+ SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0)
+ SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0)
+ SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0)
+
+ li r3, 0 ; return UNW_ESUCCESS
+ blr
+
+
+
+#endif
+
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
new file mode 100644
index 00000000000..cac2101e4c0
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -0,0 +1,813 @@
+//===-- 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
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/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/TimeValue.h"
+
+// Project includes
+#include "StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunication constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunication::GDBRemoteCommunication() :
+ Communication("gdb-remote.packets"),
+ m_send_acks (true),
+ m_rx_packet_listener ("gdbremote.rx_packet"),
+ m_sequence_mutex (Mutex::eMutexTypeRecursive),
+ m_is_running (false),
+ m_async_mutex (Mutex::eMutexTypeRecursive),
+ m_async_packet_predicate (false),
+ m_async_packet (),
+ m_async_response (),
+ m_async_timeout (UINT32_MAX),
+ m_async_signal (-1),
+ m_arch(),
+ m_os(),
+ m_vendor(),
+ m_byte_order(eByteOrderHost),
+ m_pointer_byte_size(0)
+{
+ m_rx_packet_listener.StartListeningForEvents(this,
+ Communication::eBroadcastBitPacketAvailable |
+ Communication::eBroadcastBitReadThreadDidExit);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunication::~GDBRemoteCommunication()
+{
+ m_rx_packet_listener.StopListeningForEvents(this,
+ Communication::eBroadcastBitPacketAvailable |
+ Communication::eBroadcastBitReadThreadDidExit);
+ if (IsConnected())
+ {
+ StopReadThread();
+ Disconnect();
+ }
+}
+
+
+char
+GDBRemoteCommunication::CalculcateChecksum (const char *payload, size_t payload_length)
+{
+ int checksum = 0;
+
+ // We only need to compute the checksum if we are sending acks
+ if (m_send_acks)
+ {
+ for (int i = 0; i < payload_length; ++i)
+ checksum += payload[i];
+ }
+ return checksum & 255;
+}
+
+size_t
+GDBRemoteCommunication::SendAck (char ack_char)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS, "send packet: %c", ack_char);
+ ConnectionStatus status = eConnectionStatusSuccess;
+ return Write (&ack_char, 1, status, NULL) == 1;
+}
+
+size_t
+GDBRemoteCommunication::SendPacketAndWaitForResponse
+(
+ const char *payload,
+ StringExtractorGDBRemote &response,
+ uint32_t timeout_seconds,
+ bool send_async
+)
+{
+ return SendPacketAndWaitForResponse (payload,
+ ::strlen (payload),
+ response,
+ timeout_seconds,
+ send_async);
+}
+
+size_t
+GDBRemoteCommunication::SendPacketAndWaitForResponse
+(
+ const char *payload,
+ size_t payload_length,
+ StringExtractorGDBRemote &response,
+ uint32_t timeout_seconds,
+ bool send_async
+)
+{
+ Mutex::Locker locker;
+ TimeValue timeout_time;
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds (timeout_seconds);
+
+ if (locker.TryLock (m_sequence_mutex.GetMutex()))
+ {
+ if (SendPacketNoLock (payload, strlen(payload)))
+ return WaitForPacketNoLock (response, &timeout_time);
+ }
+ else
+ {
+ if (send_async)
+ {
+ Mutex::Locker async_locker (m_async_mutex);
+ m_async_packet.assign(payload, payload_length);
+ m_async_timeout = timeout_seconds;
+ m_async_packet_predicate.SetValue (true, eBroadcastNever);
+
+ bool timed_out = false;
+ if (SendInterrupt(1, &timed_out))
+ {
+ if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out))
+ {
+ response = m_async_response;
+ return response.GetStringRef().size();
+ }
+ }
+// if (timed_out)
+// m_error.SetErrorString("Timeout.");
+// else
+// m_error.SetErrorString("Unknown error.");
+ }
+ else
+ {
+// m_error.SetErrorString("Sequence mutex is locked.");
+ }
+ }
+ return 0;
+}
+
+//template<typename _Tp>
+//class ScopedValueChanger
+//{
+//public:
+// // Take a value reference and the value to assing it to when this class
+// // instance goes out of scope.
+// ScopedValueChanger (_Tp &value_ref, _Tp value) :
+// m_value_ref (value_ref),
+// m_value (value)
+// {
+// }
+//
+// // This object is going out of scope, change the value pointed to by
+// // m_value_ref to the value we got during construction which was stored in
+// // m_value;
+// ~ScopedValueChanger ()
+// {
+// m_value_ref = m_value;
+// }
+//protected:
+// _Tp &m_value_ref; // A reference to the value we wil change when this object destructs
+// _Tp m_value; // The value to assign to m_value_ref when this goes out of scope.
+//};
+
+StateType
+GDBRemoteCommunication::SendContinuePacketAndWaitForResponse
+(
+ ProcessGDBRemote *process,
+ const char *payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response
+)
+{
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS);
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s ()", __FUNCTION__);
+
+ Mutex::Locker locker(m_sequence_mutex);
+ m_is_running.SetValue (true, eBroadcastNever);
+
+// ScopedValueChanger<bool> restore_running_to_false (m_is_running, false);
+ StateType state = eStateRunning;
+
+ if (SendPacket(payload, packet_length) == 0)
+ state = eStateInvalid;
+
+ while (state == eStateRunning)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () WaitForPacket(...)", __FUNCTION__);
+
+ if (WaitForPacket (response, (TimeValue*)NULL))
+ {
+ if (response.Empty())
+ state = eStateInvalid;
+ else
+ {
+ const char stop_type = response.GetChar();
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () got '%c' packet", __FUNCTION__, stop_type);
+ switch (stop_type)
+ {
+ case 'T':
+ case 'S':
+ if (m_async_signal != -1)
+ {
+ // 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
+ uint8_t signo = response.GetHexU8(255);
+ if (signo == async_signal)
+ {
+ // We already stopped with a signal that we wanted
+ // to stop with, so we are done
+ response.SetFilePos (0);
+ }
+ 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 (SendPacket(signal_packet, signal_packet_len) == 0)
+ {
+ state = eStateInvalid;
+ break;
+ }
+ else
+ continue;
+ }
+ }
+ else if (m_async_packet_predicate.GetValue())
+ {
+ // We are supposed to send an asynchronous packet while
+ // we are running.
+ m_async_response.Clear();
+ if (!m_async_packet.empty())
+ {
+ SendPacketAndWaitForResponse (m_async_packet.data(),
+ m_async_packet.size(),
+ m_async_response,
+ m_async_timeout,
+ false);
+ }
+ // Let the other thread that was trying to send the async
+ // packet know that the packet has been sent.
+ m_async_packet_predicate.SetValue(false, eBroadcastAlways);
+
+ // Continue again
+ if (SendPacket("c", 1) == 0)
+ {
+ state = eStateInvalid;
+ break;
+ }
+ else
+ continue;
+ }
+ // Stop with signal and thread info
+ state = eStateStopped;
+ break;
+
+ case 'W':
+ // process exited
+ state = eStateExited;
+ break;
+
+ case 'O':
+ // STDOUT
+ {
+ 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 'E':
+ // ERROR
+ state = eStateInvalid;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () got unrecognized async packet: '%s'", __FUNCTION__, stop_type);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () WaitForPacket(...) => false", __FUNCTION__);
+ state = eStateInvalid;
+ }
+ }
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () => %s", __FUNCTION__, StateAsCString(state));
+ response.SetFilePos(0);
+ m_is_running.SetValue (false, eBroadcastOnChange);
+ return state;
+}
+
+size_t
+GDBRemoteCommunication::SendPacket (const char *payload)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return SendPacketNoLock (payload, ::strlen (payload));
+}
+
+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));
+
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS, "send packet: %s", packet.GetData());
+ ConnectionStatus status = eConnectionStatusSuccess;
+ size_t bytes_written = Write (packet.GetData(), packet.GetSize(), status, NULL);
+ if (bytes_written == packet.GetSize())
+ {
+ if (m_send_acks)
+ GetAck (1) == '+';
+ }
+ return bytes_written;
+ }
+ //m_error.SetErrorString("Not connected.");
+ return 0;
+}
+
+char
+GDBRemoteCommunication::GetAck (uint32_t timeout_seconds)
+{
+ StringExtractorGDBRemote response;
+ if (WaitForPacket (response, timeout_seconds) == 1)
+ return response.GetChar();
+ return 0;
+}
+
+bool
+GDBRemoteCommunication::GetSequenceMutex (Mutex::Locker& locker)
+{
+ return locker.TryLock (m_sequence_mutex.GetMutex());
+}
+
+bool
+GDBRemoteCommunication::SendAsyncSignal (int signo)
+{
+ m_async_signal = signo;
+ bool timed_out = false;
+ if (SendInterrupt(1, &timed_out))
+ return true;
+ m_async_signal = -1;
+ return false;
+}
+
+bool
+GDBRemoteCommunication::SendInterrupt (uint32_t seconds_to_wait_for_stop, bool *timed_out)
+{
+ if (timed_out)
+ *timed_out = false;
+
+ if (IsConnected() && IsRunning())
+ {
+ // Only send an interrupt if our debugserver is running...
+ if (m_sequence_mutex.TryLock() != 0)
+ {
+ // 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;
+ TimeValue timeout;
+ if (seconds_to_wait_for_stop)
+ {
+ timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds (seconds_to_wait_for_stop);
+ }
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS, "send packet: \\x03");
+ if (Write (&ctrl_c, 1, status, NULL) > 0)
+ {
+ if (seconds_to_wait_for_stop)
+ m_is_running.WaitForValueEqualTo (false, &timeout, timed_out);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+size_t
+GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, uint32_t timeout_seconds)
+{
+ TimeValue timeout_time;
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds (timeout_seconds);
+ return WaitForPacketNoLock (response, &timeout_time);
+}
+
+size_t
+GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, TimeValue* timeout_time_ptr)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return WaitForPacketNoLock (response, timeout_time_ptr);
+}
+
+size_t
+GDBRemoteCommunication::WaitForPacketNoLock (StringExtractorGDBRemote &response, TimeValue* timeout_time_ptr)
+{
+ bool checksum_error = false;
+ response.Clear ();
+
+ EventSP event_sp;
+
+ if (m_rx_packet_listener.WaitForEvent (timeout_time_ptr, event_sp))
+ {
+ const uint32_t event_type = event_sp->GetType();
+ if (event_type | Communication::eBroadcastBitPacketAvailable)
+ {
+ const EventDataBytes *event_bytes = EventDataBytes::GetEventDataFromEvent(event_sp.get());
+ if (event_bytes)
+ {
+ const char * packet_data = (const char *)event_bytes->GetBytes();
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS, "read packet: %s", packet_data);
+ const size_t packet_size = event_bytes->GetByteSize();
+ if (packet_data && packet_size > 0)
+ {
+ std::string &response_str = response.GetStringRef();
+ if (packet_data[0] == '$')
+ {
+ assert (packet_size >= 4); // Must have at least '$#CC' where CC is checksum
+ assert (packet_data[packet_size-3] == '#');
+ assert (::isxdigit (packet_data[packet_size-2])); // Must be checksum hex byte
+ assert (::isxdigit (packet_data[packet_size-1])); // Must be checksum hex byte
+ response_str.assign (packet_data + 1, packet_size - 4);
+ if (m_send_acks)
+ {
+ char packet_checksum = strtol (&packet_data[packet_size-2], NULL, 16);
+ char actual_checksum = CalculcateChecksum (response_str.data(), response_str.size());
+ checksum_error = packet_checksum != actual_checksum;
+ // Send the ack or nack if needed
+ if (checksum_error)
+ SendAck('-');
+ else
+ SendAck('+');
+ }
+ }
+ else
+ {
+ response_str.assign (packet_data, packet_size);
+ }
+ return response_str.size();
+ }
+ }
+ }
+ else if (Communication::eBroadcastBitReadThreadDidExit)
+ {
+ // Our read thread exited on us so just fall through and return zero...
+ }
+ }
+ return 0;
+}
+
+void
+GDBRemoteCommunication::AppendBytesToCache (const uint8_t *src, size_t src_len, bool broadcast)
+{
+ // Put the packet data into the buffer in a thread safe fashion
+ Mutex::Locker locker(m_bytes_mutex);
+ m_bytes.append ((const char *)src, src_len);
+
+ // Parse up the packets into gdb remote packets
+ while (!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 end_idx = 0;
+
+ switch (m_bytes[0])
+ {
+ case '+': // Look for ack
+ case '-': // Look for cancel
+ case '\x03': // ^C to halt target
+ end_idx = 1; // The command is one byte long...
+ break;
+
+ case '$':
+ // Look for a standard gdb packet?
+ end_idx = m_bytes.find('#');
+ if (end_idx != std::string::npos)
+ {
+ if (end_idx + 2 < m_bytes.size())
+ {
+ end_idx += 3;
+ }
+ else
+ {
+ // Checksum bytes aren't all here yet
+ end_idx = std::string::npos;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (end_idx == std::string::npos)
+ {
+ //ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS | GDBR_LOG_VERBOSE, "GDBRemoteCommunication::%s packet not yet complete: '%s'",__FUNCTION__, m_bytes.c_str());
+ return;
+ }
+ else if (end_idx > 0)
+ {
+ // We have a valid packet...
+ assert (end_idx <= m_bytes.size());
+ std::auto_ptr<EventDataBytes> event_bytes_ap (new EventDataBytes (&m_bytes[0], end_idx));
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_COMM, "got full packet: %s", event_bytes_ap->GetBytes());
+ BroadcastEvent (eBroadcastBitPacketAvailable, event_bytes_ap.release());
+ m_bytes.erase(0, end_idx);
+ }
+ else
+ {
+ assert (1 <= m_bytes.size());
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_COMM, "GDBRemoteCommunication::%s tossing junk byte at %c",__FUNCTION__, m_bytes[0]);
+ m_bytes.erase(0, 1);
+ }
+ }
+}
+
+lldb::pid_t
+GDBRemoteCommunication::GetCurrentProcessID (uint32_t timeout_seconds)
+{
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, timeout_seconds, false))
+ {
+ if (response.GetChar() == 'Q')
+ if (response.GetChar() == 'C')
+ return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID);
+ }
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+bool
+GDBRemoteCommunication::GetLaunchSuccess (uint32_t timeout_seconds, std::string &error_str)
+{
+ error_str.clear();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, timeout_seconds, false))
+ {
+ if (response.IsOKPacket())
+ 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 ("failed to send the qLaunchSuccess packet");
+ }
+ return false;
+}
+
+int
+GDBRemoteCommunication::SendArgumentsPacket (char const *argv[], uint32_t timeout_seconds)
+{
+ 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, eByteOrderHost, eByteOrderHost);
+ }
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, timeout_seconds, false))
+ {
+ if (response.IsOKPacket())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunication::SendEnvironmentPacket (char const *name_equal_value, uint32_t timeout_seconds)
+{
+ 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, timeout_seconds, false))
+ {
+ if (response.IsOKPacket())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+bool
+GDBRemoteCommunication::GetHostInfo (uint32_t timeout_seconds)
+{
+ m_arch.Clear();
+ m_os.Clear();
+ m_vendor.Clear();
+ m_byte_order = eByteOrderHost;
+ m_pointer_byte_size = 0;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qHostInfo", response, timeout_seconds, false))
+ {
+ if (response.IsUnsupportedPacket())
+ return false;
+
+
+ std::string name;
+ std::string value;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("cputype") == 0)
+ {
+ // exception type in big endian hex
+ m_arch.SetCPUType(Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0));
+ }
+ else if (name.compare("cpusubtype") == 0)
+ {
+ // exception count in big endian hex
+ m_arch.SetCPUSubtype(Args::StringToUInt32 (value.c_str(), 0, 0));
+ }
+ else if (name.compare("ostype") == 0)
+ {
+ // exception data in big endian hex
+ m_os.SetCString(value.c_str());
+ }
+ else if (name.compare("vendor") == 0)
+ {
+ m_vendor.SetCString(value.c_str());
+ }
+ else if (name.compare("endian") == 0)
+ {
+ if (value.compare("little") == 0)
+ m_byte_order = eByteOrderLittle;
+ else if (value.compare("big") == 0)
+ m_byte_order = eByteOrderBig;
+ else if (value.compare("pdp") == 0)
+ m_byte_order = eByteOrderPDP;
+ }
+ else if (name.compare("ptrsize") == 0)
+ {
+ m_pointer_byte_size = Args::StringToUInt32 (value.c_str(), 0, 0);
+ }
+ }
+ }
+ return HostInfoIsValid();
+}
+
+int
+GDBRemoteCommunication::SendAttach
+(
+ lldb::pid_t pid,
+ uint32_t timeout_seconds,
+ StringExtractorGDBRemote& response
+)
+{
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ StreamString packet;
+ packet.Printf("vAttach;%x", pid);
+
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, timeout_seconds, false))
+ {
+ if (response.IsErrorPacket())
+ return response.GetError();
+ return 0;
+ }
+ }
+ return -1;
+}
+
+const lldb_private::ArchSpec &
+GDBRemoteCommunication::GetHostArchitecture ()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_arch;
+}
+
+const lldb_private::ConstString &
+GDBRemoteCommunication::GetOSString ()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_os;
+}
+
+const lldb_private::ConstString &
+GDBRemoteCommunication::GetVendorString()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_vendor;
+}
+
+lldb::ByteOrder
+GDBRemoteCommunication::GetByteOrder ()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_byte_order;
+}
+
+uint32_t
+GDBRemoteCommunication::GetAddressByteSize ()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_pointer_byte_size;
+}
+
+addr_t
+GDBRemoteCommunication::AllocateMemory (size_t size, uint32_t permissions, uint32_t timeout_seconds)
+{
+ char packet[64];
+ ::snprintf (packet, sizeof(packet), "_M%zx,%s%s%s", size,
+ permissions & lldb::ePermissionsReadable ? "r" : "",
+ permissions & lldb::ePermissionsWritable ? "w" : "",
+ permissions & lldb::ePermissionsExecutable ? "x" : "");
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, response, timeout_seconds, false))
+ {
+ if (!response.IsErrorPacket())
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+GDBRemoteCommunication::DeallocateMemory (addr_t addr, uint32_t timeout_seconds)
+{
+ char packet[64];
+ snprintf(packet, sizeof(packet), "_m%llx", (uint64_t)addr);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, response, timeout_seconds, false))
+ {
+ if (!response.IsOKPacket())
+ return true;
+ }
+ return false;
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
new file mode 100644
index 00000000000..051fa445ff1
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -0,0 +1,270 @@
+//===-- 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-private.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Predicate.h"
+
+#include "StringExtractorGDBRemote.h"
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunication :
+ public lldb_private::Communication
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteCommunication();
+
+ virtual
+ ~GDBRemoteCommunication();
+
+ size_t
+ SendPacket (const char *payload);
+
+ size_t
+ SendPacket (const char *payload,
+ size_t payload_length);
+
+ size_t
+ SendPacketAndWaitForResponse (const char *send_payload,
+ StringExtractorGDBRemote &response,
+ uint32_t timeout_seconds,
+ bool send_async);
+
+ size_t
+ SendPacketAndWaitForResponse (const char *send_payload,
+ size_t send_length,
+ StringExtractorGDBRemote &response,
+ uint32_t timeout_seconds,
+ bool send_async);
+
+ lldb::StateType
+ SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process,
+ const char *packet_payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response);
+
+ // Wait for a packet within 'nsec' seconds
+ size_t
+ WaitForPacket (StringExtractorGDBRemote &response,
+ uint32_t nsec);
+
+ // Wait for a packet with an absolute timeout time. If 'timeout' is NULL
+ // wait indefinitely.
+ size_t
+ WaitForPacket (StringExtractorGDBRemote &response,
+ lldb_private::TimeValue* timeout);
+
+ char
+ GetAck (uint32_t timeout_seconds);
+
+ size_t
+ SendAck (char ack_char);
+
+ char
+ CalculcateChecksum (const char *payload,
+ size_t payload_length);
+
+ void
+ SetAckMode (bool enabled)
+ {
+ m_send_acks = enabled;
+ }
+
+ bool
+ SendAsyncSignal (int signo);
+
+ bool
+ SendInterrupt (uint32_t seconds_to_wait_for_stop, bool *timed_out = NULL);
+
+ bool
+ GetSequenceMutex(lldb_private::Mutex::Locker& locker);
+
+ //------------------------------------------------------------------
+ // Communication overrides
+ //------------------------------------------------------------------
+ virtual void
+ AppendBytesToCache (const uint8_t *src, size_t src_len, bool broadcast);
+
+
+ lldb::pid_t
+ GetCurrentProcessID (uint32_t timeout_seconds);
+
+ bool
+ GetLaunchSuccess (uint32_t timeout_seconds, std::string &error_str);
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @param[in] timeout_seconds
+ /// The number of seconds to wait for a response from the remote
+ /// server.
+ ///
+ /// @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[], uint32_t timeout_seconds);
+
+ //------------------------------------------------------------------
+ /// 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 enironment
+ /// in the format "NAME=VALUE".
+ ///
+ /// @param[in] timeout_seconds
+ /// The number of seconds to wait for a response from the remote
+ /// server.
+ ///
+ /// @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,
+ uint32_t timeout_seconds);
+
+ //------------------------------------------------------------------
+ /// Sends a "vAttach:PID" where PID is in hex.
+ ///
+ /// @param[in] pid
+ /// A process ID for the remote gdb server to attach to.
+ ///
+ /// @param[in] timeout_seconds
+ /// The number of seconds to wait for a response from the remote
+ /// server.
+ ///
+ /// @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,
+ uint32_t timeout_seconds,
+ StringExtractorGDBRemote& response);
+
+
+ lldb::addr_t
+ AllocateMemory (size_t size, uint32_t permissions, uint32_t timeout_seconds);
+
+ bool
+ DeallocateMemory (lldb::addr_t addr, uint32_t timeout_seconds);
+
+ bool
+ IsRunning() const
+ {
+ return m_is_running.GetValue();
+ }
+
+ bool
+ GetHostInfo (uint32_t timeout_seconds);
+
+ bool
+ HostInfoIsValid () const
+ {
+ return m_pointer_byte_size != 0;
+ }
+
+ const lldb_private::ArchSpec &
+ GetHostArchitecture ();
+
+ const lldb_private::ConstString &
+ GetOSString ();
+
+ const lldb_private::ConstString &
+ GetVendorString();
+
+ lldb::ByteOrder
+ GetByteOrder ();
+
+ uint32_t
+ GetAddressByteSize ();
+
+protected:
+ typedef std::list<std::string> packet_collection;
+
+ size_t
+ SendPacketNoLock (const char *payload,
+ size_t payload_length);
+
+ size_t
+ WaitForPacketNoLock (StringExtractorGDBRemote &response,
+ lldb_private::TimeValue* timeout_time_ptr);
+
+ //------------------------------------------------------------------
+ // Classes that inherit from GDBRemoteCommunication can see and modify these
+ //------------------------------------------------------------------
+ bool m_send_acks;
+ lldb_private::Listener m_rx_packet_listener;
+ lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time
+ lldb_private::Predicate<bool> m_is_running;
+
+ // 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;
+ uint32_t m_async_timeout;
+ int m_async_signal; // We were asked to deliver a signal to the inferior process.
+
+ lldb_private::ArchSpec m_arch; // Results from the qHostInfo call
+ uint32_t m_cpusubtype; // Results from the qHostInfo call
+ lldb_private::ConstString m_os; // Results from the qHostInfo call
+ lldb_private::ConstString m_vendor; // Results from the qHostInfo call
+ lldb::ByteOrder m_byte_order; // Results from the qHostInfo call
+ uint32_t m_pointer_byte_size; // Results from the qHostInfo call
+
+
+private:
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunication only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunication);
+};
+
+#endif // liblldb_GDBRemoteCommunication_h_
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
new file mode 100644
index 00000000000..a64e74dc963
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -0,0 +1,508 @@
+//===-- 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/Scalar.h"
+#include "lldb/Core/StreamString.h"
+// Project includes
+#include "StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ThreadGDBRemote.h"
+#include "ARM_GCC_Registers.h"
+#include "ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// GDBRemoteRegisterContext constructor
+//----------------------------------------------------------------------
+GDBRemoteRegisterContext::GDBRemoteRegisterContext
+(
+ ThreadGDBRemote &thread,
+ StackFrame *frame,
+ GDBRemoteDynamicRegisterInfo &reg_info,
+ bool read_all_at_once
+) :
+ RegisterContext (thread, frame),
+ 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()
+{
+}
+
+ProcessGDBRemote &
+GDBRemoteRegisterContext::GetGDBProcess()
+{
+ return static_cast<ProcessGDBRemote &>(m_thread.GetProcess());
+}
+
+ThreadGDBRemote &
+GDBRemoteRegisterContext::GetGDBThread()
+{
+ return static_cast<ThreadGDBRemote &>(m_thread);
+}
+
+void
+GDBRemoteRegisterContext::Invalidate ()
+{
+ 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 lldb::RegisterInfo *
+GDBRemoteRegisterContext::GetRegisterInfoAtIndex (uint32_t reg)
+{
+ return m_reg_info.GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+GDBRemoteRegisterContext::GetRegisterSetCount ()
+{
+ return m_reg_info.GetNumRegisterSets ();
+}
+
+
+
+const lldb::RegisterSet *
+GDBRemoteRegisterContext::GetRegisterSet (uint32_t reg_set)
+{
+ return m_reg_info.GetRegisterSet (reg_set);
+}
+
+
+
+bool
+GDBRemoteRegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value)
+{
+ // Read the register
+ if (ReadRegisterBytes (reg, m_reg_data))
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ uint32_t offset = reg_info->byte_offset;
+ switch (reg_info->encoding)
+ {
+ case eEncodingUint:
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ value = m_reg_data.GetMaxU32 (&offset, reg_info->byte_size);
+ return true;
+
+ case 8:
+ value = m_reg_data.GetMaxU64 (&offset, reg_info->byte_size);
+ return true;
+ }
+ break;
+
+ case eEncodingSint:
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ value = (int32_t)m_reg_data.GetMaxU32 (&offset, reg_info->byte_size);
+ return true;
+
+ case 8:
+ value = m_reg_data.GetMaxS64 (&offset, reg_info->byte_size);
+ return true;
+ }
+ break;
+
+ case eEncodingIEEE754:
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ value = m_reg_data.GetFloat (&offset);
+ return true;
+
+ case sizeof (double):
+ value = m_reg_data.GetDouble (&offset);
+ return true;
+
+ case sizeof (long double):
+ value = m_reg_data.GetLongDouble (&offset);
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+
+bool
+GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
+{
+ GDBRemoteCommunication &gdb_comm = GetGDBProcess().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;
+
+ if (m_reg_valid_stop_id != m_thread.GetProcess().GetStopID())
+ {
+ Invalidate();
+ m_reg_valid_stop_id = m_thread.GetProcess().GetStopID();
+ }
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ assert (reg_info);
+ if (m_reg_valid[reg] == false)
+ {
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker))
+ {
+ if (GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
+ {
+ char packet[32];
+ StringExtractorGDBRemote response;
+ int packet_len;
+ if (m_read_all_at_once)
+ {
+ // Get all registers in one packet
+ packet_len = ::snprintf (packet, sizeof(packet), "g");
+ assert (packet_len < (sizeof(packet) - 1));
+ if (gdb_comm.SendPacketAndWaitForResponse(packet, response, 1, false))
+ {
+ if (response.IsNormalPacket())
+ if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
+ SetAllRegisterValid (true);
+ }
+ }
+ else
+ {
+ // Get each register individually
+ packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg, false);
+ assert (packet_len < (sizeof(packet) - 1));
+ if (gdb_comm.SendPacketAndWaitForResponse(packet, response, 1, false))
+ if (response.GetHexBytes ((uint8_t*)m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size), reg_info->byte_size, '\xcc') == reg_info->byte_size)
+ m_reg_valid[reg] = true;
+ }
+ }
+ }
+ }
+
+ bool reg_is_valid = m_reg_valid[reg];
+ if (reg_is_valid)
+ {
+ 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 reg_is_valid;
+}
+
+
+bool
+GDBRemoteRegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value)
+{
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info)
+ {
+ DataExtractor data;
+ if (value.GetData (data, reg_info->byte_size))
+ return WriteRegisterBytes (reg, data, 0);
+ }
+ return false;
+}
+
+
+bool
+GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
+{
+ GDBRemoteCommunication &gdb_comm = GetGDBProcess().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;
+
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+
+ if (reg_info)
+ {
+ // Grab a pointer to where we are going to put this register
+ uint8_t *dst = (uint8_t *)m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size);
+
+ if (dst == NULL)
+ return false;
+
+ // Grab a pointer to where we are going to grab the new value from
+ const uint8_t *src = data.PeekData(0, reg_info->byte_size);
+
+ if (src == NULL)
+ return false;
+
+ if (data.GetByteOrder() == m_reg_data.GetByteOrder())
+ {
+ // No swapping, just copy the bytes
+ ::memcpy (dst, src, reg_info->byte_size);
+ }
+ else
+ {
+ // Swap the bytes
+ for (uint32_t i=0; i<reg_info->byte_size; ++i)
+ dst[i] = src[reg_info->byte_size - 1 - i];
+ }
+
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker))
+ {
+ if (GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
+ {
+ uint32_t offset, end_offset;
+ StreamString packet;
+ StringExtractorGDBRemote response;
+ if (m_read_all_at_once)
+ {
+ // Get all registers in one packet
+ packet.PutChar ('G');
+ offset = 0;
+ end_offset = m_reg_data.GetByteSize();
+
+ packet.PutBytesAsRawHex8 (m_reg_data.GetDataStart(),
+ m_reg_data.GetByteSize(),
+ eByteOrderHost,
+ eByteOrderHost);
+
+ // Invalidate all register values
+ Invalidate ();
+
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ 1,
+ false))
+ {
+ SetAllRegisterValid (false);
+ if (response.IsOKPacket())
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ // Get each register individually
+ packet.Printf ("P%x=", reg);
+ packet.PutBytesAsRawHex8 (m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size),
+ reg_info->byte_size,
+ eByteOrderHost,
+ eByteOrderHost);
+
+ // Invalidate just this register
+ m_reg_valid[reg] = false;
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ 1,
+ false))
+ {
+ if (response.IsOKPacket())
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+bool
+GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
+ StringExtractorGDBRemote response;
+ if (gdb_comm.SendPacketAndWaitForResponse("g", response, 1, false))
+ {
+ if (response.IsErrorPacket())
+ return false;
+
+ response.GetStringRef().insert(0, 1, 'G');
+ data_sp.reset (new DataBufferHeap(response.GetStringRef().data(),
+ response.GetStringRef().size()));
+ return true;
+ }
+ return false;
+}
+
+bool
+GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
+ StringExtractorGDBRemote response;
+ if (gdb_comm.SendPacketAndWaitForResponse((const char *)data_sp->GetBytes(),
+ data_sp->GetByteSize(),
+ response,
+ 1,
+ false))
+ {
+ if (response.IsOKPacket())
+ return true;
+ }
+ return false;
+}
+
+
+uint32_t
+GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+void
+GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters()
+{
+ static lldb::RegisterInfo
+ g_register_infos[] =
+ {
+ // NAME ALT SZ OFF ENCODING FORMAT NUM COMPILER DWARF GENERIC
+ // ====== ======= == ==== ============= ============ === =============== =============== =========
+ { "r0", NULL, 4, 0, eEncodingUint, eFormatHex, 0, { gcc_r0, dwarf_r0, LLDB_INVALID_REGNUM }},
+ { "r1", NULL, 4, 4, eEncodingUint, eFormatHex, 1, { gcc_r1, dwarf_r1, LLDB_INVALID_REGNUM }},
+ { "r2", NULL, 4, 8, eEncodingUint, eFormatHex, 2, { gcc_r2, dwarf_r2, LLDB_INVALID_REGNUM }},
+ { "r3", NULL, 4, 12, eEncodingUint, eFormatHex, 3, { gcc_r3, dwarf_r3, LLDB_INVALID_REGNUM }},
+ { "r4", NULL, 4, 16, eEncodingUint, eFormatHex, 4, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM }},
+ { "r5", NULL, 4, 20, eEncodingUint, eFormatHex, 5, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM }},
+ { "r6", NULL, 4, 24, eEncodingUint, eFormatHex, 6, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM }},
+ { "r7", NULL, 4, 28, eEncodingUint, eFormatHex, 7, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP }},
+ { "r8", NULL, 4, 32, eEncodingUint, eFormatHex, 8, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM }},
+ { "r9", NULL, 4, 36, eEncodingUint, eFormatHex, 9, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM }},
+ { "r10", NULL, 4, 40, eEncodingUint, eFormatHex, 10, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM }},
+ { "r11", NULL, 4, 44, eEncodingUint, eFormatHex, 11, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM }},
+ { "r12", NULL, 4, 48, eEncodingUint, eFormatHex, 12, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM }},
+ { "sp", "r13", 4, 52, eEncodingUint, eFormatHex, 13, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP }},
+ { "lr", "r14", 4, 56, eEncodingUint, eFormatHex, 14, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA }},
+ { "pc", "r15", 4, 60, eEncodingUint, eFormatHex, 15, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC }},
+ { NULL, NULL, 12, 64, eEncodingIEEE754, eFormatFloat, 16, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 76, eEncodingIEEE754, eFormatFloat, 17, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 88, eEncodingIEEE754, eFormatFloat, 18, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 100, eEncodingIEEE754, eFormatFloat, 19, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 112, eEncodingIEEE754, eFormatFloat, 20, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 124, eEncodingIEEE754, eFormatFloat, 21, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 136, eEncodingIEEE754, eFormatFloat, 22, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 148, eEncodingIEEE754, eFormatFloat, 23, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { NULL, NULL, 12, 160, eEncodingIEEE754, eFormatFloat, 24, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS }},
+ { "cpsr", "psr", 4, 172, eEncodingUint, eFormatHex, 25, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS }},
+ { "s0", NULL, 4, 176, eEncodingIEEE754, eFormatFloat, 26, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM }},
+ { "s1", NULL, 4, 180, eEncodingIEEE754, eFormatFloat, 27, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM }},
+ { "s2", NULL, 4, 184, eEncodingIEEE754, eFormatFloat, 28, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM }},
+ { "s3", NULL, 4, 188, eEncodingIEEE754, eFormatFloat, 29, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM }},
+ { "s4", NULL, 4, 192, eEncodingIEEE754, eFormatFloat, 30, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM }},
+ { "s5", NULL, 4, 196, eEncodingIEEE754, eFormatFloat, 31, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM }},
+ { "s6", NULL, 4, 200, eEncodingIEEE754, eFormatFloat, 32, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM }},
+ { "s7", NULL, 4, 204, eEncodingIEEE754, eFormatFloat, 33, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM }},
+ { "s8", NULL, 4, 208, eEncodingIEEE754, eFormatFloat, 34, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM }},
+ { "s9", NULL, 4, 212, eEncodingIEEE754, eFormatFloat, 35, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM }},
+ { "s10", NULL, 4, 216, eEncodingIEEE754, eFormatFloat, 36, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM }},
+ { "s11", NULL, 4, 220, eEncodingIEEE754, eFormatFloat, 37, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM }},
+ { "s12", NULL, 4, 224, eEncodingIEEE754, eFormatFloat, 38, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM }},
+ { "s13", NULL, 4, 228, eEncodingIEEE754, eFormatFloat, 39, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM }},
+ { "s14", NULL, 4, 232, eEncodingIEEE754, eFormatFloat, 40, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM }},
+ { "s15", NULL, 4, 236, eEncodingIEEE754, eFormatFloat, 41, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM }},
+ { "s16", NULL, 4, 240, eEncodingIEEE754, eFormatFloat, 42, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM }},
+ { "s17", NULL, 4, 244, eEncodingIEEE754, eFormatFloat, 43, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM }},
+ { "s18", NULL, 4, 248, eEncodingIEEE754, eFormatFloat, 44, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM }},
+ { "s19", NULL, 4, 252, eEncodingIEEE754, eFormatFloat, 45, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM }},
+ { "s20", NULL, 4, 256, eEncodingIEEE754, eFormatFloat, 46, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM }},
+ { "s21", NULL, 4, 260, eEncodingIEEE754, eFormatFloat, 47, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM }},
+ { "s22", NULL, 4, 264, eEncodingIEEE754, eFormatFloat, 48, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM }},
+ { "s23", NULL, 4, 268, eEncodingIEEE754, eFormatFloat, 49, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM }},
+ { "s24", NULL, 4, 272, eEncodingIEEE754, eFormatFloat, 50, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM }},
+ { "s25", NULL, 4, 276, eEncodingIEEE754, eFormatFloat, 51, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM }},
+ { "s26", NULL, 4, 280, eEncodingIEEE754, eFormatFloat, 52, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM }},
+ { "s27", NULL, 4, 284, eEncodingIEEE754, eFormatFloat, 53, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM }},
+ { "s28", NULL, 4, 288, eEncodingIEEE754, eFormatFloat, 54, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM }},
+ { "s29", NULL, 4, 292, eEncodingIEEE754, eFormatFloat, 55, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM }},
+ { "s30", NULL, 4, 296, eEncodingIEEE754, eFormatFloat, 56, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM }},
+ { "s31", NULL, 4, 300, eEncodingIEEE754, eFormatFloat, 57, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM }},
+ { "fpscr", NULL, 4, 304, eEncodingUint, eFormatHex, 58, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM }},
+ { "d16", NULL, 8, 308, eEncodingIEEE754, eFormatFloat, 59, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM }},
+ { "d17", NULL, 8, 316, eEncodingIEEE754, eFormatFloat, 60, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM }},
+ { "d18", NULL, 8, 324, eEncodingIEEE754, eFormatFloat, 61, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM }},
+ { "d19", NULL, 8, 332, eEncodingIEEE754, eFormatFloat, 62, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM }},
+ { "d20", NULL, 8, 340, eEncodingIEEE754, eFormatFloat, 63, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM }},
+ { "d21", NULL, 8, 348, eEncodingIEEE754, eFormatFloat, 64, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM }},
+ { "d22", NULL, 8, 356, eEncodingIEEE754, eFormatFloat, 65, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM }},
+ { "d23", NULL, 8, 364, eEncodingIEEE754, eFormatFloat, 66, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM }},
+ { "d24", NULL, 8, 372, eEncodingIEEE754, eFormatFloat, 67, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM }},
+ { "d25", NULL, 8, 380, eEncodingIEEE754, eFormatFloat, 68, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM }},
+ { "d26", NULL, 8, 388, eEncodingIEEE754, eFormatFloat, 69, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM }},
+ { "d27", NULL, 8, 396, eEncodingIEEE754, eFormatFloat, 70, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM }},
+ { "d28", NULL, 8, 404, eEncodingIEEE754, eFormatFloat, 71, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM }},
+ { "d29", NULL, 8, 412, eEncodingIEEE754, eFormatFloat, 72, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM }},
+ { "d30", NULL, 8, 420, eEncodingIEEE754, eFormatFloat, 73, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM }},
+ { "d31", NULL, 8, 428, eEncodingIEEE754, eFormatFloat, 74, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM }},
+ };
+ static const uint32_t num_registers = sizeof (g_register_infos)/sizeof (lldb::RegisterInfo);
+ static ConstString gpr_reg_set ("General Purpose Registers");
+ static ConstString vfp_reg_set ("Floating Point Registers");
+ for (uint32_t 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);
+
+ AddRegister (g_register_infos[i], name, alt_name, i < 26 ? gpr_reg_set : vfp_reg_set);
+ }
+}
+
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
new file mode 100644
index 00000000000..67acdefdce0
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -0,0 +1,250 @@
+//===-- 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/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/RegisterContext.h"
+
+
+class ThreadGDBRemote;
+class ProcessGDBRemote;
+
+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::RegisterInfo &reg_info, lldb_private::ConstString &reg_name, lldb_private::ConstString &reg_alt_name, lldb_private::ConstString &set_name)
+ {
+ const uint32_t reg_num = 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);
+ 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
+ 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::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t i) const
+ {
+ if (i < m_regs.size())
+ return &m_regs[i];
+ return NULL;
+ }
+
+ const lldb::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, 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);
+ lldb::RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ return 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 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();
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from GDBRemoteRegisterContext can see and modify these
+ //------------------------------------------------------------------
+ typedef std::vector <lldb::RegisterInfo> reg_collection;
+ typedef std::vector <lldb::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_reg_names;
+ name_collection m_reg_alt_names;
+ name_collection m_set_names;
+ 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,
+ lldb_private::StackFrame *frame,
+ GDBRemoteDynamicRegisterInfo &reg_info,
+ bool read_all_at_once);
+
+ virtual
+ ~GDBRemoteRegisterContext ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ Invalidate ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb::RegisterSet *
+ GetRegisterSet (uint32_t reg_set);
+
+ virtual bool
+ ReadRegisterValue (uint32_t reg, lldb_private::Scalar &value);
+
+ virtual bool
+ ReadRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegisterValue (uint32_t reg, const lldb_private::Scalar &value);
+
+ virtual bool
+ WriteRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data, uint32_t data_offset);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+protected:
+
+ void
+ SetAllRegisterValid (bool b);
+
+ ProcessGDBRemote &
+ GetGDBProcess();
+
+ ThreadGDBRemote &
+ GetGDBThread();
+
+ GDBRemoteDynamicRegisterInfo &m_reg_info;
+ std::vector<bool> m_reg_valid;
+ uint32_t m_reg_valid_stop_id;
+ lldb_private::DataExtractor m_reg_data;
+ bool m_read_all_at_once;
+
+private:
+ //------------------------------------------------------------------
+ // For GDBRemoteRegisterContext only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteRegisterContext);
+};
+
+#endif // lldb_GDBRemoteRegisterContext_h_
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBServer.cpp
new file mode 100644
index 00000000000..a88ec7b09d4
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBServer.cpp
@@ -0,0 +1,1148 @@
+//===-- GDBServer.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <getopt.h>
+#include <netinet/in.h>
+#include <sys/select.h>
+#include <sys/sysctl.h>
+#include <string>
+#include <vector>
+#include <asl.h>
+
+#include "GDBServerLog.h"
+#include "GDBRemoteSession.h"
+
+using namespace lldb;
+
+//----------------------------------------------------------------------
+// Run loop modes which determine which run loop function will be called
+//----------------------------------------------------------------------
+typedef enum
+{
+ eDCGSRunLoopModeInvalid = 0,
+ eDCGSRunLoopModeGetStartModeFromRemoteProtocol,
+ eDCGSRunLoopModeInferiorAttaching,
+ eDCGSRunLoopModeInferiorLaunching,
+ eDCGSRunLoopModeInferiorExecuting,
+ eDCGSRunLoopModeInferiorKillOrDetach,
+ eDCGSRunLoopModeExit
+} GSRunLoopMode;
+
+typedef enum
+{
+ eLaunchFlavorDefault = 0,
+ eLaunchFlavorPosixSpawn,
+#if defined (__arm__)
+ eLaunchFlavorSpringBoard,
+#endif
+ eLaunchFlavorForkExec,
+} GSLaunchFlavor;
+
+typedef lldb::shared_ptr<GDBRemoteSession> GDBRemoteSP;
+
+typedef struct HandleBroadcastEventInfo
+{
+ TargetSP target_sp;
+ GDBRemoteSP remote_sp;
+ GSRunLoopMode mode;
+
+ Target *
+ GetTarget ()
+ {
+ return target_sp.get();
+ }
+
+ Process *
+ GetProcess()
+ {
+ if (target_sp.get())
+ return target_sp->GetProcess().get();
+ return NULL;
+ }
+
+ GDBRemoteSession *
+ GetRemote ()
+ {
+ return remote_sp.get();
+ }
+
+};
+
+
+//----------------------------------------------------------------------
+// Global Variables
+//----------------------------------------------------------------------
+static int g_lockdown_opt = 0;
+static int g_applist_opt = 0;
+static GSLaunchFlavor g_launch_flavor = eLaunchFlavorDefault;
+int g_isatty = 0;
+
+//----------------------------------------------------------------------
+// Run Loop function prototypes
+//----------------------------------------------------------------------
+void GSRunLoopGetStartModeFromRemote (HandleBroadcastEventInfo *info);
+void GSRunLoopInferiorExecuting (HandleBroadcastEventInfo *info);
+
+
+//----------------------------------------------------------------------
+// Get our program path and arguments from the remote connection.
+// We will need to start up the remote connection without a PID, get the
+// arguments, wait for the new process to finish launching and hit its
+// entry point, and then return the run loop mode that should come next.
+//----------------------------------------------------------------------
+void
+GSRunLoopGetStartModeFromRemote (HandleBroadcastEventInfo *info)
+{
+ std::string packet;
+
+ Target *target = info->GetTarget();
+ GDBRemoteSession *remote = info->GetRemote();
+ if (target != NULL && remote != NULL)
+ {
+ // Spin waiting to get the A packet.
+ while (1)
+ {
+ gdb_err_t err = gdb_err;
+ GDBRemoteSession::PacketEnum type;
+
+ err = remote->HandleReceivedPacket (&type);
+
+ // check if we tried to attach to a process
+ if (type == GDBRemoteSession::vattach || type == GDBRemoteSession::vattachwait)
+ {
+ if (err == gdb_success)
+ {
+ info->mode = eDCGSRunLoopModeInferiorExecuting;
+ return;
+ }
+ else
+ {
+ Log::STDERR ("error: attach failed.");
+ info->mode = eDCGSRunLoopModeExit;
+ return;
+ }
+ }
+
+ if (err == gdb_success)
+ {
+ // If we got our arguments we are ready to launch using the arguments
+ // and any environment variables we received.
+ if (type == GDBRemoteSession::set_argv)
+ {
+ info->mode = eDCGSRunLoopModeInferiorLaunching;
+ return;
+ }
+ }
+ else if (err == gdb_not_connected)
+ {
+ Log::STDERR ("error: connection lost.");
+ info->mode = eDCGSRunLoopModeExit;
+ return;
+ }
+ else
+ {
+ // a catch all for any other gdb remote packets that failed
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Error getting packet.",__FUNCTION__);
+ continue;
+ }
+
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "#### %s", __FUNCTION__);
+ }
+ }
+ info->mode = eDCGSRunLoopModeExit;
+}
+
+
+//----------------------------------------------------------------------
+// This run loop mode will wait for the process to launch and hit its
+// entry point. It will currently ignore all events except for the
+// process state changed event, where it watches for the process stopped
+// or crash process state.
+//----------------------------------------------------------------------
+GSRunLoopMode
+GSRunLoopLaunchInferior (HandleBroadcastEventInfo *info)
+{
+ // The Process stuff takes a c array, the GSContext has a vector...
+ // So make up a c array.
+ Target *target = info->GetTarget();
+ GDBRemoteSession *remote = info->GetRemote();
+ Process* process = info->GetProcess();
+
+ if (process == NULL)
+ return eDCGSRunLoopModeExit;
+
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Launching '%s'...", __FUNCTION__, target->GetExecutableModule()->GetFileSpec().GetFilename().AsCString());
+
+ // Our launch type hasn't been set to anything concrete, so we need to
+ // figure our how we are going to launch automatically.
+
+ GSLaunchFlavor launch_flavor = g_launch_flavor;
+ if (launch_flavor == eLaunchFlavorDefault)
+ {
+ // Our default launch method is posix spawn
+ launch_flavor = eLaunchFlavorPosixSpawn;
+
+#if defined (__arm__)
+ // Check if we have an app bundle, if so launch using SpringBoard.
+ if (strstr(inferior_argv[0], ".app"))
+ {
+ launch_flavor = eLaunchFlavorSpringBoard;
+ }
+#endif
+ }
+
+ //ctx.SetLaunchFlavor(launch_flavor);
+
+ const char *stdio_file = NULL;
+ lldb::pid_t pid = process->Launch (remote->GetARGV(), remote->GetENVP(), stdio_file, stdio_file, stdio_file);
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ Log::STDERR ("error: process launch failed: %s", process->GetError().AsCString());
+ }
+ else
+ {
+ if (remote->IsConnected())
+ {
+ // It we are connected already, the next thing gdb will do is ask
+ // whether the launch succeeded, and if not, whether there is an
+ // error code. So we need to fetch one packet from gdb before we wait
+ // on the stop from the target.
+ gdb_err_t err = gdb_err;
+ GDBRemoteSession::PacketEnum type;
+
+ err = remote->HandleReceivedPacket (&type);
+
+ if (err != gdb_success)
+ {
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Error getting packet.", __FUNCTION__);
+ return eDCGSRunLoopModeExit;
+ }
+ if (type != GDBRemoteSession::query_launch_success)
+ {
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__);
+ }
+ }
+ }
+
+ Listener listener("GSRunLoopLaunchInferior");
+ listener.StartListeningForEvents (process, Process::eBroadcastBitStateChanged);
+ while (process->GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ uint32_t event_mask = 0;
+ while (listener.WaitForEvent(NULL, &event_mask))
+ {
+ if (event_mask & Process::eBroadcastBitStateChanged)
+ {
+ Event event;
+ StateType event_state;
+ while ((event_state = process->GetNextEvent (&event)))
+ if (StateIsStoppedState(event_state))
+ {
+ GDBServerLog::LogIf (GS_LOG_EVENTS, "%s process %4.4x stopped with state %s", __FUNCTION__, pid, StateAsCString(event_state));
+
+ switch (event_state)
+ {
+ default:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateSuspended:
+ break; // Ignore
+
+ case eStateRunning:
+ case eStateStepping:
+ // Still waiting to stop at entry point...
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ return eDCGSRunLoopModeInferiorExecuting;
+
+ case eStateDetached:
+ case eStateExited:
+ pid = LLDB_INVALID_PROCESS_ID;
+ return eDCGSRunLoopModeExit;
+ }
+ }
+
+ if (event_state = eStateInvalid)
+ break;
+ }
+ }
+ }
+
+ return eDCGSRunLoopModeExit;
+}
+
+
+//----------------------------------------------------------------------
+// This run loop mode will wait for the process to launch and hit its
+// entry point. It will currently ignore all events except for the
+// process state changed event, where it watches for the process stopped
+// or crash process state.
+//----------------------------------------------------------------------
+GSRunLoopMode
+GSRunLoopLaunchAttaching (HandleBroadcastEventInfo *info, lldb::pid_t& pid)
+{
+ Process* process = info->GetProcess();
+
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, pid);
+ pid = process->Attach(pid);
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return eDCGSRunLoopModeExit;
+ return eDCGSRunLoopModeInferiorExecuting;
+}
+
+//----------------------------------------------------------------------
+// Watch for signals:
+// SIGINT: so we can halt our inferior. (disabled for now)
+// SIGPIPE: in case our child process dies
+//----------------------------------------------------------------------
+lldb::pid_t g_pid;
+int g_sigpipe_received = 0;
+void
+signal_handler(int signo)
+{
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (%s)", __FUNCTION__, Host::GetSignalAsCString(signo));
+
+ switch (signo)
+ {
+// case SIGINT:
+// DNBProcessKill (g_pid, signo);
+// break;
+
+ case SIGPIPE:
+ g_sigpipe_received = 1;
+ break;
+ }
+}
+
+// Return the new run loop mode based off of the current process state
+void
+HandleProcessStateChange (HandleBroadcastEventInfo *info, bool initialize)
+{
+ Process *process = info->GetProcess();
+ if (process == NULL)
+ {
+ info->mode = eDCGSRunLoopModeExit;
+ return;
+ }
+
+ if (process->GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__);
+ info->mode = eDCGSRunLoopModeExit;
+ return;
+ }
+ StateType pid_state = process->GetState ();
+
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (info, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, StateAsCString(pid_state));
+
+ switch (pid_state)
+ {
+ case eStateInvalid:
+ case eStateUnloaded:
+ // Something bad happened
+ info->mode = eDCGSRunLoopModeExit;
+ return;
+
+ case eStateAttaching:
+ case eStateLaunching:
+ info->mode = eDCGSRunLoopModeInferiorExecuting;
+ return;
+
+ case eStateSuspended:
+ case eStateCrashed:
+ case eStateStopped:
+ if (initialize == false)
+ {
+ // Compare the last stop count to our current notion of a stop count
+ // to make sure we don't notify more than once for a given stop.
+ static uint32_t g_prev_stop_id = 0;
+ uint32_t stop_id = process->GetStopID();
+ bool pid_stop_count_changed = g_prev_stop_id != stop_id;
+ if (pid_stop_count_changed)
+ {
+ info->GetRemote()->FlushSTDIO();
+
+ if (stop_id == 1)
+ {
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, StateAsCString (pid_state), stop_id, g_prev_stop_id);
+ }
+ else
+ {
+
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? YES!!!", __FUNCTION__, (int)initialize, StateAsCString (pid_state), stop_id, g_prev_stop_id);
+ info->GetRemote()->NotifyThatProcessStopped ();
+ }
+ }
+ else
+ {
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? skipping...", __FUNCTION__, (int)initialize, StateAsCString (pid_state), stop_id, g_prev_stop_id);
+ }
+ }
+ info->mode = eDCGSRunLoopModeInferiorExecuting;
+ return;
+
+ case eStateStepping:
+ case eStateRunning:
+ info->mode = eDCGSRunLoopModeInferiorExecuting;
+ return;
+
+ case eStateExited:
+ info->GetRemote()->HandlePacket_last_signal (NULL);
+ info->mode = eDCGSRunLoopModeExit;
+ return;
+
+ }
+
+ // Catch all...
+ info->mode = eDCGSRunLoopModeExit;
+}
+
+bool
+CommunicationHandleBroadcastEvent (Broadcaster *broadcaster, uint32_t event_mask, void *baton)
+{
+ HandleBroadcastEventInfo *info = (HandleBroadcastEventInfo *)baton;
+ Process *process = info->GetProcess();
+
+ if (process == NULL)
+ {
+ info->mode = eDCGSRunLoopModeExit;
+ return true;
+ }
+
+ if (event_mask & Communication::eBroadcastBitPacketAvailable)
+ {
+ if (process->IsRunning())
+ {
+ if (info->GetRemote()->HandleAsyncPacket() == gdb_not_connected)
+ info->mode = eDCGSRunLoopModeExit;
+ }
+ else
+ {
+ if (info->GetRemote()->HandleReceivedPacket() == gdb_not_connected)
+ info->mode = eDCGSRunLoopModeExit;
+ }
+ }
+ if (event_mask & Communication::eBroadcastBitReadThreadDidExit)
+ {
+ info->mode = eDCGSRunLoopModeExit;
+ }
+ if (event_mask & Communication::eBroadcastBitDisconnected)
+ {
+ info->mode = eDCGSRunLoopModeExit;
+ }
+
+ return true;
+
+}
+
+bool
+ProcessHandleBroadcastEvent (Broadcaster *broadcaster, uint32_t event_mask, void *baton)
+{
+ HandleBroadcastEventInfo *info = (HandleBroadcastEventInfo *)baton;
+ Process *process = info->GetProcess();
+ if (process == NULL)
+ {
+ info->mode = eDCGSRunLoopModeExit;
+ return true;
+ }
+
+ if (event_mask & Process::eBroadcastBitStateChanged)
+ {
+ // Consume all available process events with no timeout
+ Event event;
+ StateType process_state;
+ while ((process_state = process->GetNextEvent (&event)) != eStateInvalid)
+ {
+ if (StateIsStoppedState(process_state))
+ info->GetRemote()->FlushSTDIO();
+ HandleProcessStateChange (info, false);
+
+ if (info->mode != eDCGSRunLoopModeInferiorExecuting)
+ break;
+ }
+ }
+ else
+ if (event_mask & (Process::eBroadcastBitSTDOUT | Process::eBroadcastBitSTDERR))
+ {
+ info->GetRemote()->FlushSTDIO();
+ }
+ return true;
+}
+
+// This function handles the case where our inferior program is stopped and
+// we are waiting for gdb remote protocol packets. When a packet occurs that
+// makes the inferior run, we need to leave this function with a new state
+// as the return code.
+void
+GSRunLoopInferiorExecuting (HandleBroadcastEventInfo *info)
+{
+ GDBServerLog::LogIf (GS_LOG_MINIMAL, "#### %s", __FUNCTION__);
+
+ // Init our mode and set 'is_running' based on the current process state
+ HandleProcessStateChange (info, true);
+
+ uint32_t desired_mask, acquired_mask;
+ Listener listener("GSRunLoopInferiorExecuting");
+
+ desired_mask = Communication::eBroadcastBitPacketAvailable |
+ Communication::eBroadcastBitReadThreadDidExit |
+ Communication::eBroadcastBitDisconnected;
+
+ acquired_mask = listener.StartListeningForEvents (&(info->GetRemote()->GetPacketComm()),
+ desired_mask,
+ CommunicationHandleBroadcastEvent,
+ info);
+
+ assert (acquired_mask == desired_mask);
+ desired_mask = GDBRemotePacket::eBroadcastBitPacketAvailable;
+
+ acquired_mask = listener.StartListeningForEvents (&(info->GetRemote()->GetPacketComm()),
+ desired_mask,
+ CommunicationHandleBroadcastEvent,
+ info);
+
+ assert (acquired_mask == desired_mask);
+
+ desired_mask = Process::eBroadcastBitStateChanged |
+ Process::eBroadcastBitSTDOUT |
+ Process::eBroadcastBitSTDERR ;
+ acquired_mask = listener.StartListeningForEvents (info->GetProcess (),
+ desired_mask,
+ ProcessHandleBroadcastEvent,
+ info);
+
+ assert (acquired_mask == desired_mask);
+
+ Process *process = info->GetProcess();
+
+ while (process->IsAlive())
+ {
+ if (!info->GetRemote()->IsConnected())
+ {
+ info->mode = eDCGSRunLoopModeInferiorKillOrDetach;
+ break;
+ }
+
+ // We want to make sure we consume all process state changes and have
+ // whomever is notifying us to wait for us to reset the event bit before
+ // continuing.
+ //ctx.Events().SetResetAckMask (GSContext::event_proc_state_changed);
+ uint32_t event_mask = 0;
+ Broadcaster *broadcaster = listener.WaitForEvent(NULL, &event_mask);
+ if (broadcaster)
+ {
+ listener.HandleBroadcastEvent(broadcaster, event_mask);
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Convenience function to set up the remote listening port
+// Returns 1 for success 0 for failure.
+//----------------------------------------------------------------------
+
+static bool
+StartListening (HandleBroadcastEventInfo *info, int listen_port)
+{
+ if (!info->GetRemote()->IsConnected())
+ {
+ Log::STDOUT ("Listening to port %i...\n", listen_port);
+ char connect_url[256];
+ snprintf(connect_url, sizeof(connect_url), "listen://%i", listen_port);
+
+ Communication &comm = info->remote_sp->GetPacketComm();
+ comm.SetConnection (new ConnectionFileDescriptor);
+
+ if (comm.Connect (connect_url))
+ {
+ if (comm.StartReadThread())
+ return true;
+
+ Log::STDERR ("Failed to start the communication read thread.\n", connect_url);
+ comm.Disconnect();
+ }
+ else
+ {
+ Log::STDERR ("Failed to connection to %s.\n", connect_url);
+ }
+ return false;
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------
+// ASL Logging callback that can be registered with DNBLogSetLogDCScriptInterpreter::Type
+//----------------------------------------------------------------------
+//void
+//ASLLogDCScriptInterpreter::Type(void *baton, uint32_t flags, const char *format, va_list args)
+//{
+// if (format == NULL)
+// return;
+// static aslmsg g_aslmsg = NULL;
+// if (g_aslmsg == NULL)
+// {
+// g_aslmsg = ::asl_new (ASL_TYPE_MSG);
+// char asl_key_sender[PATH_MAX];
+// snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.dc-gdbserver-%g", dc_gdbserverVersionNumber);
+// ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
+// }
+//
+// int asl_level;
+// if (flags & DNBLOG_FLAG_FATAL) asl_level = ASL_LEVEL_CRIT;
+// else if (flags & DNBLOG_FLAG_ERROR) asl_level = ASL_LEVEL_ERR;
+// else if (flags & DNBLOG_FLAG_WARNING) asl_level = ASL_LEVEL_WARNING;
+// else if (flags & DNBLOG_FLAG_VERBOSE) asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_INFO;
+// else asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_DEBUG;
+//
+// ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
+//}
+
+//----------------------------------------------------------------------
+// FILE based Logging callback that can be registered with
+// DNBLogSetLogDCScriptInterpreter::Type
+//----------------------------------------------------------------------
+void
+FileLogDCScriptInterpreter::Type(void *baton, uint32_t flags, const char *format, va_list args)
+{
+ if (baton == NULL || format == NULL)
+ return;
+
+ ::vfprintf ((FILE *)baton, format, args);
+ ::fprintf ((FILE *)baton, "\n");
+}
+
+//----------------------------------------------------------------------
+// option descriptors for getopt_long()
+//----------------------------------------------------------------------
+static struct option g_long_options[] =
+{
+ { "arch", required_argument, NULL, 'c' },
+ { "attach", required_argument, NULL, 'a' },
+ { "debug", no_argument, NULL, 'g' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "lockdown", no_argument, &g_lockdown_opt, 1 }, // short option "-k"
+ { "applist", no_argument, &g_applist_opt, 1 }, // short option "-t"
+ { "log-file", required_argument, NULL, 'l' },
+ { "log-flags", required_argument, NULL, 'f' },
+ { "launch", required_argument, NULL, 'x' }, // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only)
+ { "waitfor", required_argument, NULL, 'w' }, // Wait for a process whose namet starts with ARG
+ { "waitfor-interval", required_argument, NULL, 'i' }, // Time in usecs to wait between sampling the pid list when waiting for a process by name
+ { "waitfor-duration", required_argument, NULL, 'd' }, // The time in seconds to wait for a process to show up by name
+ { NULL, 0, NULL, 0 }
+};
+
+extern const double dc_gdbserverVersionNumber;
+int
+main (int argc, char *argv[])
+{
+ Initialize();
+ Host::ThreadCreated ("[main]");
+
+ g_isatty = ::isatty (STDIN_FILENO);
+
+// signal (SIGINT, signal_handler);
+ signal (SIGPIPE, signal_handler);
+
+ Log *log = GDBServerLog::GetLogIfAllCategoriesSet(GS_LOG_ALL);
+ const char *this_exe_name = argv[0];
+ int i;
+ int attach_pid = LLDB_INVALID_PROCESS_ID;
+ for (i=0; i<argc; i++)
+ GDBServerLog::LogIf(GS_LOG_DEBUG, "argv[%i] = %s", i, argv[i]);
+
+ FILE* log_file = NULL;
+ uint32_t log_flags = 0;
+ // Parse our options
+ int ch;
+ int long_option_index = 0;
+ int debug = 0;
+ std::string waitfor_pid_name; // Wait for a process that starts with this name
+ std::string attach_pid_name;
+ useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
+ useconds_t waitfor_duration = 0; // Time in seconds to wait for a process by name, 0 means wait forever.
+ ArchSpec arch;
+ GSRunLoopMode start_mode = eDCGSRunLoopModeExit;
+
+ while ((ch = getopt_long(argc, argv, "a:c:d:gi:vktl:f:w:x:", g_long_options, &long_option_index)) != -1)
+ {
+// DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n",
+// ch, (uint8_t)ch,
+// g_long_options[long_option_index].name,
+// g_long_options[long_option_index].has_arg ? '=' : ' ',
+// optarg ? optarg : "");
+ switch (ch)
+ {
+ case 0: // Any optional that auto set themselves will return 0
+ break;
+
+ case 'c':
+ arch.SetArch(optarg);
+ if (!arch.IsValid())
+ {
+ Log::STDERR ("error: invalid arch string '%s'\n", optarg);
+ exit (8);
+ }
+ break;
+
+ case 'a':
+ if (optarg && optarg[0])
+ {
+ if (isdigit(optarg[0]))
+ {
+ char *end = NULL;
+ attach_pid = strtoul(optarg, &end, 0);
+ if (end == NULL || *end != '\0')
+ {
+ Log::STDERR ("error: invalid pid option '%s'\n", optarg);
+ exit (4);
+ }
+ }
+ else
+ {
+ attach_pid_name = optarg;
+ }
+ start_mode = eDCGSRunLoopModeInferiorAttaching;
+ }
+ break;
+
+ // --waitfor=NAME
+ case 'w':
+ if (optarg && optarg[0])
+ {
+ waitfor_pid_name = optarg;
+ start_mode = eDCGSRunLoopModeInferiorAttaching;
+ }
+ break;
+
+ // --waitfor-interval=USEC
+ case 'i':
+ if (optarg && optarg[0])
+ {
+ char *end = NULL;
+ waitfor_interval = strtoul(optarg, &end, 0);
+ if (end == NULL || *end != '\0')
+ {
+ Log::STDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg);
+ exit (6);
+ }
+ }
+ break;
+
+ // --waitfor-duration=SEC
+ case 'd':
+ if (optarg && optarg[0])
+ {
+ char *end = NULL;
+ waitfor_duration = strtoul(optarg, &end, 0);
+ if (end == NULL || *end != '\0')
+ {
+ Log::STDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg);
+ exit (7);
+ }
+ }
+ break;
+
+ case 'x':
+ if (optarg && optarg[0])
+ {
+ if (strcasecmp(optarg, "auto") == 0)
+ g_launch_flavor = eLaunchFlavorDefault;
+ else if (strcasestr(optarg, "posix") == optarg)
+ g_launch_flavor = eLaunchFlavorPosixSpawn;
+ else if (strcasestr(optarg, "fork") == optarg)
+ g_launch_flavor = eLaunchFlavorForkExec;
+#if defined (__arm__)
+ else if (strcasestr(optarg, "spring") == optarg)
+ g_launch_flavor = eLaunchFlavorSpringBoard;
+#endif
+ else
+ {
+ Log::STDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg);
+ Log::STDERR ("Valid values TYPE are:\n");
+ Log::STDERR (" auto Auto-detect the best launch method to use.\n");
+ Log::STDERR (" posix Launch the executable using posix_spawn.\n");
+ Log::STDERR (" fork Launch the executable using fork and exec.\n");
+#if defined (__arm__)
+ Log::STDERR (" spring Launch the executable through Springboard.\n");
+#endif
+ exit (5);
+ }
+ }
+ break;
+
+ case 'l': // Set Log File
+ if (optarg && optarg[0])
+ {
+ if (strcasecmp(optarg, "stdout") == 0)
+ log_file = stdout;
+ else if (strcasecmp(optarg, "stderr") == 0)
+ log_file = stderr;
+ else
+ log_file = fopen(optarg, "w+");
+
+ if (log_file == NULL)
+ {
+ const char *errno_str = strerror(errno);
+ Log::STDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
+ }
+ }
+ break;
+
+ case 'f': // Log Flags
+ if (optarg && optarg[0])
+ log_flags = strtoul(optarg, NULL, 0);
+ break;
+
+ case 'g':
+ debug = 1;
+ //DNBLogSetDebug(1);
+ break;
+
+ case 't':
+ g_applist_opt = 1;
+ break;
+
+ case 'k':
+ g_lockdown_opt = 1;
+ break;
+
+ case 'v':
+ //DNBLogSetVerbose(1);
+ break;
+ }
+ }
+
+ // Skip any options we consumed with getopt_long
+ argc -= optind;
+ argv += optind;
+
+ // It is ok for us to set NULL as the logfile (this will disable any logging)
+
+// if (log_file != NULL)
+// {
+// DNBLogSetLogDCScriptInterpreter::Type(FileLogDCScriptInterpreter::Type, log_file);
+// // If our log file was set, yet we have no log flags, log everything!
+// if (log_flags == 0)
+// log_flags = LOG_ALL | LOG_DCGS_ALL;
+//
+// DNBLogSetLogMask (log_flags);
+// }
+// else
+// {
+// // Enable DNB logging
+// DNBLogSetLogDCScriptInterpreter::Type(ASLLogDCScriptInterpreter::Type, NULL);
+// DNBLogSetLogMask (log_flags);
+//
+// }
+
+ // as long as we're dropping remotenub in as a replacement for gdbserver,
+ // explicitly note that this is not gdbserver.
+
+ Log::STDOUT ("debugserver-%g \n", dc_gdbserverVersionNumber);
+ int listen_port = -1;
+ if (g_lockdown_opt == 0 && g_applist_opt == 0)
+ {
+ // Make sure we at least have port
+ if (argc < 1)
+ {
+ Log::STDERR ("Usage: %s host:port [program-name program-arg1 program-arg2 ...]\n", this_exe_name);
+ exit (1);
+ }
+ // accept 'localhost:' prefix on port number
+
+ std::string host_str;
+ std::string port_str(argv[0]);
+
+ // We just used the host:port arg...
+ argc--;
+ argv++;
+
+ size_t port_idx = port_str.find(':');
+ if (port_idx != std::string::npos)
+ {
+ host_str.assign(port_str, 0, port_idx);
+ port_str.erase(0, port_idx + 1);
+ }
+
+ if (port_str.empty())
+ {
+ Log::STDERR ("error: no port specified\nUsage: %s host:port [program-name program-arg1 program-arg2 ...]\n", this_exe_name);
+ exit (2);
+ }
+ else if (port_str.find_first_not_of("0123456789") != std::string::npos)
+ {
+ Log::STDERR ("error: port must be an integer: %s\nUsage: %s host:port [program-name program-arg1 program-arg2 ...]\n", port_str.c_str(), this_exe_name);
+ exit (3);
+ }
+ //DNBLogDebug("host_str = '%s' port_str = '%s'", host_str.c_str(), port_str.c_str());
+ listen_port = atoi (port_str.c_str());
+ }
+
+
+ // We must set up some communications now.
+
+ FileSpec exe_spec;
+ if (argv[0])
+ exe_spec.SetFile (argv[0]);
+
+ HandleBroadcastEventInfo info;
+ info.target_sp = TargetList::SharedList().CreateTarget(&exe_spec, &arch);
+ ProcessSP process_sp (info.target_sp->CreateProcess ());
+ info.remote_sp.reset (new GDBRemoteSession (process_sp));
+
+ info.remote_sp->SetLog (log);
+ StreamString sstr;
+ sstr.Printf("ConnectionFileDescriptor(%s)", argv[0]);
+
+ if (info.remote_sp.get() == NULL)
+ {
+ Log::STDERR ("error: failed to create a GDBRemoteSession class\n");
+ return -1;
+ }
+
+
+
+ // If we know we're waiting to attach, we don't need any of this other info.
+ if (start_mode != eDCGSRunLoopModeInferiorAttaching)
+ {
+ if (argc == 0 || g_lockdown_opt)
+ {
+ if (g_lockdown_opt != 0)
+ {
+ // Work around for SIGPIPE crashes due to posix_spawn issue. We have to close
+ // STDOUT and STDERR, else the first time we try and do any, we get SIGPIPE and
+ // die as posix_spawn is doing bad things with our file descriptors at the moment.
+ int null = open("/dev/null", O_RDWR);
+ dup2(null, STDOUT_FILENO);
+ dup2(null, STDERR_FILENO);
+ }
+ else if (g_applist_opt != 0)
+ {
+// // List all applications we are able to see
+// std::string applist_plist;
+// int err = ListApplications(applist_plist, false, false);
+// if (err == 0)
+// {
+// fputs (applist_plist.c_str(), stdout);
+// }
+// else
+// {
+// Log::STDERR ("error: ListApplications returned error %i\n", err);
+// }
+// // Exit with appropriate error if we were asked to list the applications
+// // with no other args were given (and we weren't trying to do this over
+// // lockdown)
+// return err;
+ return 0;
+ }
+
+ //DNBLogDebug("Get args from remote protocol...");
+ start_mode = eDCGSRunLoopModeGetStartModeFromRemoteProtocol;
+ }
+ else
+ {
+ start_mode = eDCGSRunLoopModeInferiorLaunching;
+ // Fill in the argv array in the context from the rest of our args.
+ // Skip the name of this executable and the port number
+ info.remote_sp->SetArguments (argc, argv);
+ }
+ }
+
+ if (start_mode == eDCGSRunLoopModeExit)
+ return -1;
+
+ info.mode = start_mode;
+
+ while (info.mode != eDCGSRunLoopModeExit)
+ {
+ switch (info.mode)
+ {
+ case eDCGSRunLoopModeGetStartModeFromRemoteProtocol:
+ #if defined (__arm__)
+ if (g_lockdown_opt)
+ {
+ if (!info.remote_sp->GetCommunication()->IsConnected())
+ {
+ if (info.remote_sp->GetCommunication()->ConnectToService () != gdb_success)
+ {
+ Log::STDERR ("Failed to get connection from a remote gdb process.\n");
+ info.mode = eDCGSRunLoopModeExit;
+ }
+ else if (g_applist_opt != 0)
+ {
+ // List all applications we are able to see
+ std::string applist_plist;
+ if (ListApplications(applist_plist, false, false) == 0)
+ {
+ //DNBLogDebug("Task list: %s", applist_plist.c_str());
+
+ info.remote_sp->GetCommunication()->Write(applist_plist.c_str(), applist_plist.size());
+ // Issue a read that will never yield any data until the other side
+ // closes the socket so this process doesn't just exit and cause the
+ // socket to close prematurely on the other end and cause data loss.
+ std::string buf;
+ info.remote_sp->GetCommunication()->Read(buf);
+ }
+ info.remote_sp->GetCommunication()->Disconnect(false);
+ info.mode = eDCGSRunLoopModeExit;
+ break;
+ }
+ else
+ {
+ // Start watching for remote packets
+ info.remote_sp->StartReadRemoteDataThread();
+ }
+ }
+ }
+ else
+#endif
+ {
+ if (StartListening (&info, listen_port))
+ Log::STDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
+ else
+ info.mode = eDCGSRunLoopModeExit;
+ }
+
+ if (info.mode != eDCGSRunLoopModeExit)
+ GSRunLoopGetStartModeFromRemote (&info);
+ break;
+
+ case eDCGSRunLoopModeInferiorAttaching:
+ if (!waitfor_pid_name.empty())
+ {
+ // Set our end wait time if we are using a waitfor-duration
+ // option that may have been specified
+
+ TimeValue attach_timeout_abstime;
+ if (waitfor_duration != 0)
+ {
+ attach_timeout_abstime = TimeValue::Now();
+ attach_timeout_abstime.OffsetWithSeconds (waitfor_duration);
+ }
+ GSLaunchFlavor launch_flavor = g_launch_flavor;
+ if (launch_flavor == eLaunchFlavorDefault)
+ {
+ // Our default launch method is posix spawn
+ launch_flavor = eLaunchFlavorPosixSpawn;
+
+#if defined (__arm__)
+ // Check if we have an app bundle, if so launch using SpringBoard.
+ if (waitfor_pid_name.find (".app") != std::string::npos)
+ {
+ launch_flavor = eLaunchFlavorSpringBoard;
+ }
+#endif
+ }
+
+ //ctx.SetLaunchFlavor(launch_flavor);
+
+
+ lldb::pid_t pid = info.GetProcess()->Attach (waitfor_pid_name.c_str());
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ info.GetRemote()->GetLaunchError() = info.GetProcess()->GetError();
+ Log::STDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), info.GetRemote()->GetLaunchError().AsCString());
+ info.mode = eDCGSRunLoopModeExit;
+ }
+ else
+ {
+ info.mode = eDCGSRunLoopModeInferiorExecuting;
+ }
+ }
+ else if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ Log::STDOUT ("Attaching to process %i...\n", attach_pid);
+ info.mode = GSRunLoopLaunchAttaching (&info, attach_pid);
+ if (info.mode != eDCGSRunLoopModeInferiorExecuting)
+ {
+ const char *error_str = info.GetRemote()->GetLaunchError().AsCString();
+ Log::STDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error.");
+ info.mode = eDCGSRunLoopModeExit;
+ }
+ }
+ else if (!attach_pid_name.empty ())
+ {
+ lldb::pid_t pid = info.GetProcess()->Attach (waitfor_pid_name.c_str());
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ info.GetRemote()->GetLaunchError() = info.GetProcess()->GetError();
+ Log::STDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), info.GetRemote()->GetLaunchError().AsCString());
+ info.mode = eDCGSRunLoopModeExit;
+ }
+ else
+ {
+ info.mode = eDCGSRunLoopModeInferiorExecuting;
+ }
+ }
+ else
+ {
+ Log::STDERR ("error: asked to attach with empty name and invalid PID.");
+ info.mode = eDCGSRunLoopModeExit;
+ }
+
+ if (info.mode != eDCGSRunLoopModeExit)
+ {
+ if (StartListening (&info, listen_port))
+ Log::STDOUT ("Got a connection, waiting for debugger instructions for process %d.\n", attach_pid);
+ else
+ info.mode = eDCGSRunLoopModeExit;
+ }
+ break;
+
+ case eDCGSRunLoopModeInferiorLaunching:
+ info.mode = GSRunLoopLaunchInferior (&info);
+
+ if (info.mode == eDCGSRunLoopModeInferiorExecuting)
+ {
+ if (StartListening (&info, listen_port))
+ Log::STDOUT ("Got a connection, waiting for debugger instructions for task \"%s\".\n", argv[0]);
+ else
+ info.mode = eDCGSRunLoopModeExit;
+ }
+ else
+ {
+ Log::STDERR ("error: failed to launch process %s: %s\n", argv[0], info.GetRemote()->GetLaunchError().AsCString());
+ }
+ break;
+
+ case eDCGSRunLoopModeInferiorExecuting:
+ GSRunLoopInferiorExecuting (&info);
+ break;
+
+ case eDCGSRunLoopModeInferiorKillOrDetach:
+ {
+ Process *process = info.GetProcess();
+ if (process && process->IsAlive())
+ {
+ process->Kill(SIGCONT);
+ process->Kill(SIGKILL);
+ }
+ }
+ info.mode = eDCGSRunLoopModeExit;
+ break;
+
+ default:
+ info.mode = eDCGSRunLoopModeExit;
+ case eDCGSRunLoopModeExit:
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBServerLog.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBServerLog.cpp
new file mode 100644
index 00000000000..2d4116ebe7b
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBServerLog.cpp
@@ -0,0 +1,80 @@
+//===-- GDBServerLog.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// GDBServerLog.cpp
+// liblldb
+//
+// Created by Greg Clayton on 6/19/09.
+//
+//
+//----------------------------------------------------------------------
+
+#include "GDBServerLog.h"
+
+using namespace lldb;
+
+static Log *
+LogAccessor (bool get, Log *log)
+{
+ static Log* g_log = NULL; // Leak for now as auto_ptr was being cleaned up
+ // by global constructors before other threads
+ // were done with it.
+ if (get)
+ {
+// // Debug code below for enabling logging by default
+// if (g_log == NULL)
+// {
+// g_log = new Log("/dev/stdout", false);
+// g_log->GetMask().SetAllFlagBits(GS_LOG_ALL);
+// g_log->GetOptions().Set(LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_THREAD_NAME);
+// }
+ }
+ else
+ {
+ if (g_log)
+ delete g_log;
+ g_log = log;
+ }
+
+ return g_log;
+}
+
+Log *
+GDBServerLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log = LogAccessor (true, NULL);
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().GetAllFlagBits();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+void
+GDBServerLog::SetLog (Log *log)
+{
+ LogAccessor (false, log);
+}
+
+
+void
+GDBServerLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log = GDBServerLog::GetLogIfAllCategoriesSet (mask);
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBServerLog.h b/lldb/source/Plugins/Process/gdb-remote/GDBServerLog.h
new file mode 100644
index 00000000000..3dec8088cef
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBServerLog.h
@@ -0,0 +1,55 @@
+//===-- GDBServerLog.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// GDBServerLog.h
+// liblldb
+//
+// Created by Greg Clayton on 6/19/09.
+//
+//
+//----------------------------------------------------------------------
+
+#ifndef liblldb_GDBServerLog_h_
+#define liblldb_GDBServerLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+#include "lldb/Core/Log.h"
+
+// Project includes
+#define GS_LOG_VERBOSE (1u << 0)
+#define GS_LOG_DEBUG (1u << 1)
+#define GS_LOG_PACKETS (1u << 2)
+#define GS_LOG_EVENTS (1u << 3)
+#define GS_LOG_MINIMAL (1u << 4)
+#define GS_LOG_ALL (UINT32_MAX)
+#define GS_LOG_DEFAULT (GS_LOG_VERBOSE |\
+ GS_LOG_PACKETS)
+
+namespace lldb {
+
+class GDBServerLog
+{
+public:
+ static Log *
+ GetLog (uint32_t mask = 0);
+
+ static void
+ SetLog (Log *log);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+} // namespace lldb
+
+#endif // liblldb_GDBServerLog_h_
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
new file mode 100644
index 00000000000..e08679c1e1c
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -0,0 +1,2272 @@
+//===-- ProcessGDBRemote.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 <mach/mach.h>
+#include <mach-o/dyld.h>
+#include <spawn.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <unistd.h>
+
+// C++ Includes
+#include <algorithm>
+#include <map>
+
+// Other libraries and framework includes
+
+#include "lldb/Breakpoint/WatchpointLocation.h"
+#include "lldb/Core/Args.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+#include "PseudoTerminal.h"
+
+// Project includes
+#include "lldb/Host/Host.h"
+#include "StringExtractorGDBRemote.h"
+#include "GDBRemoteRegisterContext.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "ThreadGDBRemote.h"
+#include "libunwind.h"
+#include "MacOSXLibunwindCallbacks.h"
+
+#if defined (__i386__) || defined (__x86_64__)
+#define MACH_EXC_DATA0_SOFTWARE_BREAKPOINT EXC_I386_BPT
+#define MACH_EXC_DATA0_TRACE EXC_I386_SGL
+#elif defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
+#define MACH_EXC_DATA0_SOFTWARE_BREAKPOINT EXC_PPC_BREAKPOINT
+#elif defined (__arm__)
+#define MACH_EXC_DATA0_SOFTWARE_BREAKPOINT EXC_ARM_BREAKPOINT
+#endif
+
+
+#define DEBUGSERVER_BASENAME "debugserver"
+using namespace lldb;
+using namespace lldb_private;
+
+static inline uint16_t
+get_random_port ()
+{
+ return (arc4random() % (UINT16_MAX - 1000u)) + 1000u;
+}
+
+
+const char *
+ProcessGDBRemote::GetPluginNameStatic()
+{
+ return "process.gdb-remote";
+}
+
+const char *
+ProcessGDBRemote::GetPluginDescriptionStatic()
+{
+ return "GDB Remote protocol based debugging plug-in.";
+}
+
+void
+ProcessGDBRemote::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessGDBRemote::CreateInstance);
+}
+
+
+Process*
+ProcessGDBRemote::CreateInstance (Target &target, Listener &listener)
+{
+ return new ProcessGDBRemote (target, listener);
+}
+
+bool
+ProcessGDBRemote::CanDebug(Target &target)
+{
+ // 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();
+ return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessGDBRemote constructor
+//----------------------------------------------------------------------
+ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
+ Process (target, listener),
+ m_dynamic_loader_ap (),
+ m_byte_order (eByteOrderHost),
+ m_flags (0),
+ m_stdio_communication ("gdb-remote.stdio"),
+ m_stdio_mutex (Mutex::eMutexTypeRecursive),
+ m_stdout_data (),
+ m_arch_spec (),
+ m_gdb_comm(),
+ m_debugserver_pid (LLDB_INVALID_PROCESS_ID),
+ m_debugserver_monitor (0),
+ m_register_info (),
+ m_curr_tid (LLDB_INVALID_THREAD_ID),
+ m_curr_tid_run (LLDB_INVALID_THREAD_ID),
+ m_async_broadcaster ("lldb.process.gdb-remote.async-broadcaster"),
+ m_async_thread (LLDB_INVALID_HOST_THREAD),
+ m_z0_supported (1),
+ m_continue_packet(),
+ m_dispatch_queue_offsets_addr (LLDB_INVALID_ADDRESS),
+ m_libunwind_target_type (UNW_TARGET_UNSPECIFIED),
+ m_libunwind_addr_space (NULL),
+ m_waiting_for_attach (false),
+ m_packet_timeout (1),
+ m_max_memory_size (512)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessGDBRemote::~ProcessGDBRemote()
+{
+ // m_mach_process.UnregisterNotificationCallbacks (this);
+ Clear();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+const char *
+ProcessGDBRemote::GetPluginName()
+{
+ return "Process debugging plug-in that uses the GDB remote protocol";
+}
+
+const char *
+ProcessGDBRemote::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessGDBRemote::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ProcessGDBRemote::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+ strm->Printf("TODO: fill this in\n");
+}
+
+Error
+ProcessGDBRemote::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in commands are currently supported.");
+ return error;
+}
+
+Log *
+ProcessGDBRemote::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+void
+ProcessGDBRemote::BuildDynamicRegisterInfo ()
+{
+ char register_info_command[64];
+ m_register_info.Clear();
+ StringExtractorGDBRemote::Type packet_type = StringExtractorGDBRemote::eResponse;
+ uint32_t reg_offset = 0;
+ uint32_t reg_num = 0;
+ for (; packet_type == StringExtractorGDBRemote::eResponse; ++reg_num)
+ {
+ ::snprintf (register_info_command, sizeof(register_info_command), "qRegisterInfo%x", reg_num);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(register_info_command, response, 2, false))
+ {
+ packet_type = response.GetType();
+ if (packet_type == StringExtractorGDBRemote::eResponse)
+ {
+ std::string name;
+ std::string value;
+ ConstString reg_name;
+ ConstString alt_name;
+ ConstString set_name;
+ RegisterInfo reg_info = { NULL, // Name
+ NULL, // Alt name
+ 0, // byte size
+ reg_offset, // offset
+ eEncodingUint, // encoding
+ eFormatHex, // formate
+ reg_num, // native register number
+ {
+ LLDB_INVALID_REGNUM, // GCC reg num
+ LLDB_INVALID_REGNUM, // DWARF reg num
+ LLDB_INVALID_REGNUM, // generic reg num
+ reg_num // GDB reg num
+ }
+ };
+
+ 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 (offset != offset)
+ {
+ reg_offset = offset;
+ reg_info.byte_offset = offset;
+ }
+ }
+ else if (name.compare("encoding") == 0)
+ {
+ if (value.compare("uint") == 0)
+ reg_info.encoding = eEncodingUint;
+ else if (value.compare("sint") == 0)
+ reg_info.encoding = eEncodingSint;
+ else if (value.compare("ieee754") == 0)
+ reg_info.encoding = eEncodingIEEE754;
+ else if (value.compare("vector") == 0)
+ reg_info.encoding = eEncodingVector;
+ }
+ else if (name.compare("format") == 0)
+ {
+ 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)
+ {
+ if (value.compare("pc") == 0)
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ else if (value.compare("sp") == 0)
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+ else if (value.compare("fp") == 0)
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if (value.compare("ra") == 0)
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
+ else if (value.compare("flags") == 0)
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ }
+ }
+
+ assert (reg_info.byte_size != 0);
+ reg_offset += reg_info.byte_size;
+ m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name);
+ }
+ }
+ else
+ {
+ packet_type = StringExtractorGDBRemote::eError;
+ }
+ }
+
+ if (reg_num == 0)
+ {
+ // We didn't get anything. 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.
+ ArchSpec arm_arch ("arm");
+ if (GetTarget().GetArchitecture() == arm_arch)
+ m_register_info.HardcodeARMRegisters();
+ }
+ m_register_info.Finalize ();
+}
+
+Error
+ProcessGDBRemote::WillLaunch (Module* module)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::WillAttach (lldb::pid_t pid)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::WillAttach (const char *process_name, bool wait_for_launch)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::WillLaunchOrAttach ()
+{
+ Error error;
+ // TODO: this is hardcoded for macosx right now. We need this to be more dynamic
+ m_dynamic_loader_ap.reset(DynamicLoader::FindPlugin(this, "dynamic-loader.macosx-dyld"));
+
+ if (m_dynamic_loader_ap.get() == NULL)
+ error.SetErrorString("unable to find the dynamic loader named 'dynamic-loader.macosx-dyld'");
+ m_stdio_communication.Clear ();
+
+ return error;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessGDBRemote::DoLaunch
+(
+ Module* module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path
+)
+{
+ // ::LogSetBitMask (GDBR_LOG_DEFAULT);
+ // ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
+ // ::LogSetLogFile ("/dev/stdout");
+ Error error;
+
+ ObjectFile * object_file = module->GetObjectFile();
+ if (object_file)
+ {
+ ArchSpec inferior_arch(module->GetArchitecture());
+ char host_port[128];
+ snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
+
+ bool start_debugserver_with_inferior_args = false;
+ if (start_debugserver_with_inferior_args)
+ {
+ // We want to launch debugserver with the inferior program and its
+ // arguments on the command line. We should only do this if we
+ // the GDB server we are talking to doesn't support the 'A' packet.
+ error = StartDebugserverProcess (host_port,
+ argv,
+ envp,
+ NULL, //stdin_path,
+ LLDB_INVALID_PROCESS_ID,
+ NULL, false,
+ inferior_arch);
+ if (error.Fail())
+ return error;
+
+ error = ConnectToDebugserver (host_port);
+ if (error.Success())
+ {
+ SetID (m_gdb_comm.GetCurrentProcessID (m_packet_timeout));
+ }
+ }
+ else
+ {
+ error = StartDebugserverProcess (host_port,
+ NULL,
+ NULL,
+ NULL, //stdin_path,
+ LLDB_INVALID_PROCESS_ID,
+ NULL, false,
+ inferior_arch);
+ if (error.Fail())
+ return error;
+
+ error = ConnectToDebugserver (host_port);
+ if (error.Success())
+ {
+ // Send the environment and the program + arguments after we connect
+ if (envp)
+ {
+ const char *env_entry;
+ for (int i=0; (env_entry = envp[i]); ++i)
+ {
+ if (m_gdb_comm.SendEnvironmentPacket(env_entry, m_packet_timeout) != 0)
+ break;
+ }
+ }
+
+ const uint32_t arg_timeout_seconds = 10;
+ int arg_packet_err = m_gdb_comm.SendArgumentsPacket (argv, arg_timeout_seconds);
+ if (arg_packet_err == 0)
+ {
+ std::string error_str;
+ if (m_gdb_comm.GetLaunchSuccess (m_packet_timeout, error_str))
+ {
+ SetID (m_gdb_comm.GetCurrentProcessID (m_packet_timeout));
+ }
+ else
+ {
+ error.SetErrorString (error_str.c_str());
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'A' packet returned an error: %i.\n", arg_packet_err);
+ }
+
+ SetID (m_gdb_comm.GetCurrentProcessID (m_packet_timeout));
+ }
+ }
+
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ KillDebugserverProcess ();
+ return error;
+ }
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, response, m_packet_timeout, false))
+ SetPrivateState (SetThreadStopInfo (response));
+
+ }
+ 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.\n", module->GetFileSpec().GetFilename().AsCString(), module->GetArchitecture().AsCString());
+ }
+
+ // Return the process ID we have
+ return error;
+}
+
+
+Error
+ProcessGDBRemote::ConnectToDebugserver (const char *host_port)
+{
+ Error error;
+ // Sleep and wait a bit for debugserver to start to listen...
+ std::auto_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+ if (conn_ap.get())
+ {
+ std::string connect_url("connect://");
+ connect_url.append (host_port);
+ const uint32_t max_retry_count = 50;
+ uint32_t retry_count = 0;
+ while (!m_gdb_comm.IsConnected())
+ {
+ if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
+ {
+ m_gdb_comm.SetConnection (conn_ap.release());
+ 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;
+ }
+
+ m_gdb_comm.SetAckMode (true);
+ if (m_gdb_comm.StartReadThread(&error))
+ {
+ // Send an initial ack
+ m_gdb_comm.SendAck('+');
+
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ m_debugserver_monitor = Host::StartMonitoringChildProcess (MonitorDebugserverProcess,
+ (void*)(intptr_t)GetID(), // Pass the inferior pid in the thread argument (which is a void *)
+ m_debugserver_pid,
+ false);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse("QStartNoAckMode", response, 1, false))
+ {
+ if (response.IsOKPacket())
+ m_gdb_comm.SetAckMode (false);
+ }
+
+ BuildDynamicRegisterInfo ();
+ }
+ return error;
+}
+
+void
+ProcessGDBRemote::DidLaunchOrAttach ()
+{
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PROCESS, "ProcessGDBRemote::DidLaunch()");
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ m_dynamic_loader_ap.reset();
+ }
+ else
+ {
+ m_dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS;
+
+ Module * exe_module = GetTarget().GetExecutableModule ().get();
+ assert(exe_module);
+
+ m_arch_spec = exe_module->GetArchitecture();
+
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ assert(exe_objfile);
+
+ m_byte_order = exe_objfile->GetByteOrder();
+ assert (m_byte_order != eByteOrderInvalid);
+
+ StreamString strm;
+
+ ArchSpec inferior_arch;
+ // See if the GDB server supports the qHostInfo information
+ const char *vendor = m_gdb_comm.GetVendorString().AsCString();
+ const char *os_type = m_gdb_comm.GetOSString().AsCString();
+
+ if (m_arch_spec.IsValid() && m_arch_spec == ArchSpec ("arm"))
+ {
+ // For ARM we can't trust the arch of the process as it could
+ // have an armv6 object file, but be running on armv7 kernel.
+ inferior_arch = m_gdb_comm.GetHostArchitecture();
+ }
+
+ if (!inferior_arch.IsValid())
+ inferior_arch = m_arch_spec;
+
+ if (vendor == NULL)
+ vendor = Host::GetVendorString().AsCString("apple");
+
+ if (os_type == NULL)
+ os_type = Host::GetOSString().AsCString("darwin");
+
+ strm.Printf ("%s-%s-%s", inferior_arch.AsCString(), vendor, os_type);
+
+ std::transform (strm.GetString().begin(),
+ strm.GetString().end(),
+ strm.GetString().begin(),
+ ::tolower);
+
+ m_target_triple.SetCString(strm.GetString().c_str());
+ }
+}
+
+void
+ProcessGDBRemote::DidLaunch ()
+{
+ DidLaunchOrAttach ();
+ if (m_dynamic_loader_ap.get())
+ m_dynamic_loader_ap->DidLaunch();
+}
+
+Error
+ProcessGDBRemote::DoAttach (pid_t attach_pid)
+{
+ Error error;
+ // Clear out and clean up from any current state
+ Clear();
+ // HACK: require arch be set correctly at the target level until we can
+ // figure out a good way to determine the arch of what we are attaching to
+ m_arch_spec = m_target.GetArchitecture();
+
+ //Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS);
+ if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ SetPrivateState (eStateAttaching);
+ char host_port[128];
+ snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
+ error = StartDebugserverProcess (host_port,
+ NULL,
+ NULL,
+ NULL,
+ LLDB_INVALID_PROCESS_ID,
+ NULL, false,
+ m_arch_spec);
+
+ 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 (host_port);
+ if (error.Success())
+ {
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%x", attach_pid);
+ StringExtractorGDBRemote response;
+ StateType stop_state = m_gdb_comm.SendContinuePacketAndWaitForResponse (this,
+ packet,
+ packet_len,
+ response);
+ switch (stop_state)
+ {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ SetID (attach_pid);
+ m_last_stop_packet = response;
+ m_last_stop_packet.SetFilePos (0);
+ SetPrivateState (stop_state);
+ break;
+
+ case eStateExited:
+ m_last_stop_packet = response;
+ m_last_stop_packet.SetFilePos (0);
+ response.SetFilePos(1);
+ SetExitStatus(response.GetHexU8(), NULL);
+ break;
+
+ default:
+ SetExitStatus(-1, "unable to attach to process");
+ break;
+ }
+
+ }
+ }
+ }
+
+ lldb::pid_t pid = GetID();
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ KillDebugserverProcess();
+ }
+ 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::DoAttach (const char *process_name, bool wait_for_launch)
+{
+ Error error;
+ // Clear out and clean up from any current state
+ Clear();
+ // HACK: require arch be set correctly at the target level until we can
+ // figure out a good way to determine the arch of what we are attaching to
+ m_arch_spec = m_target.GetArchitecture();
+
+ //Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS);
+ if (process_name && process_name[0])
+ {
+
+ SetPrivateState (eStateAttaching);
+ char host_port[128];
+ snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
+ error = StartDebugserverProcess (host_port,
+ NULL,
+ NULL,
+ NULL,
+ LLDB_INVALID_PROCESS_ID,
+ NULL, false,
+ m_arch_spec);
+ 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 (host_port);
+ if (error.Success())
+ {
+ StreamString packet;
+
+ packet.PutCString("vAttach");
+ if (wait_for_launch)
+ packet.PutCString("Wait");
+ packet.PutChar(';');
+ packet.PutBytesAsRawHex8(process_name, strlen(process_name), eByteOrderHost, eByteOrderHost);
+ StringExtractorGDBRemote response;
+ StateType stop_state = m_gdb_comm.SendContinuePacketAndWaitForResponse (this,
+ packet.GetData(),
+ packet.GetSize(),
+ response);
+ switch (stop_state)
+ {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ SetID (m_gdb_comm.GetCurrentProcessID(m_packet_timeout));
+ m_last_stop_packet = response;
+ m_last_stop_packet.SetFilePos (0);
+ SetPrivateState (stop_state);
+ break;
+
+ case eStateExited:
+ m_last_stop_packet = response;
+ m_last_stop_packet.SetFilePos (0);
+ response.SetFilePos(1);
+ SetExitStatus(response.GetHexU8(), NULL);
+ break;
+
+ default:
+ SetExitStatus(-1, "unable to attach to process");
+ break;
+ }
+ }
+ }
+ }
+
+ lldb::pid_t pid = GetID();
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ KillDebugserverProcess();
+ }
+ return error;
+}
+
+//
+// if (wait_for_launch)
+// {
+// InputReaderSP reader_sp (new InputReader());
+// StreamString instructions;
+// instructions.Printf("Hit any key to cancel waiting for '%s' to launch...", process_name);
+// error = reader_sp->Initialize (AttachInputReaderCallback, // callback
+// this, // baton
+// eInputReaderGranularityByte,
+// NULL, // End token
+// false);
+//
+// StringExtractorGDBRemote response;
+// m_waiting_for_attach = true;
+// FILE *reader_out_fh = reader_sp->GetOutputFileHandle();
+// while (m_waiting_for_attach)
+// {
+// // Wait for one second for the stop reply packet
+// if (m_gdb_comm.WaitForPacket(response, 1))
+// {
+// // Got some sort of packet, see if it is the stop reply packet?
+// char ch = response.GetChar(0);
+// if (ch == 'T')
+// {
+// m_waiting_for_attach = false;
+// }
+// }
+// else
+// {
+// // Put a period character every second
+// fputc('.', reader_out_fh);
+// }
+// }
+// }
+// }
+// return GetID();
+//}
+
+void
+ProcessGDBRemote::DidAttach ()
+{
+ DidLaunchOrAttach ();
+ if (m_dynamic_loader_ap.get())
+ m_dynamic_loader_ap->DidAttach();
+}
+
+Error
+ProcessGDBRemote::WillResume ()
+{
+ m_continue_packet.Clear();
+ // Start the continue packet we will use to run the target. Each thread
+ // will append what it is supposed to be doing to this packet when the
+ // ThreadList::WillResume() is called. If a thread it supposed
+ // to stay stopped, then don't append anything to this string.
+ m_continue_packet.Printf("vCont");
+ return Error();
+}
+
+Error
+ProcessGDBRemote::DoResume ()
+{
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PROCESS, "ProcessGDBRemote::Resume()");
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (m_continue_packet.GetData(), m_continue_packet.GetSize()));
+ return Error();
+}
+
+size_t
+ProcessGDBRemote::GetSoftwareBreakpointTrapOpcode (BreakpointSite* bp_site)
+{
+ const uint8_t *trap_opcode = NULL;
+ uint32_t trap_opcode_size = 0;
+
+ static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 };
+ //static const uint8_t g_thumb_breakpooint_opcode[] = { 0xFE, 0xDE };
+ static const uint8_t g_ppc_breakpoint_opcode[] = { 0x7F, 0xC0, 0x00, 0x08 };
+ static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC };
+
+ switch (m_arch_spec.GetCPUType())
+ {
+ case CPU_TYPE_ARM:
+ // TODO: fill this in for ARM. We need to dig up the symbol for
+ // the address in the breakpoint locaiton and figure out if it is
+ // an ARM or Thumb breakpoint.
+ trap_opcode = g_arm_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
+ break;
+
+ case CPU_TYPE_POWERPC:
+ case CPU_TYPE_POWERPC64:
+ trap_opcode = g_ppc_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_ppc_breakpoint_opcode);
+ break;
+
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ trap_opcode = g_i386_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_i386_breakpoint_opcode);
+ break;
+
+ default:
+ assert(!"Unhandled architecture in ProcessGDBRemote::GetSoftwareBreakpointTrapOpcode()");
+ return 0;
+ }
+
+ if (trap_opcode && trap_opcode_size)
+ {
+ if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+ }
+ return 0;
+}
+
+uint32_t
+ProcessGDBRemote::UpdateThreadListIfNeeded ()
+{
+ // locker will keep a mutex locked until it goes out of scope
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD);
+ if (log && log->GetMask().IsSet(GDBR_LOG_VERBOSE))
+ log->Printf ("ProcessGDBRemote::%s (pid = %i)", __FUNCTION__, GetID());
+
+ const uint32_t stop_id = GetStopID();
+ if (m_thread_list.GetSize(false) == 0 || stop_id != m_thread_list.GetStopID())
+ {
+ // Update the thread list's stop id immediately so we don't recurse into this function.
+ ThreadList curr_thread_list (this);
+ curr_thread_list.SetStopID(stop_id);
+
+ Error err;
+ StringExtractorGDBRemote response;
+ for (m_gdb_comm.SendPacketAndWaitForResponse("qfThreadInfo", response, 1, false);
+ response.IsNormalPacket();
+ m_gdb_comm.SendPacketAndWaitForResponse("qsThreadInfo", response, 1, false))
+ {
+ char ch = response.GetChar();
+ if (ch == 'l')
+ break;
+ if (ch == 'm')
+ {
+ do
+ {
+ tid_t tid = response.GetHexMaxU32(false, LLDB_INVALID_THREAD_ID);
+
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ ThreadSP thread_sp (GetThreadList().FindThreadByID (tid, false));
+ if (thread_sp)
+ thread_sp->GetRegisterContext()->Invalidate();
+ else
+ thread_sp.reset (new ThreadGDBRemote (*this, tid));
+ curr_thread_list.AddThread(thread_sp);
+ }
+
+ ch = response.GetChar();
+ } while (ch == ',');
+ }
+ }
+
+ m_thread_list = curr_thread_list;
+
+ SetThreadStopInfo (m_last_stop_packet);
+ }
+ return GetThreadList().GetSize(false);
+}
+
+
+StateType
+ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
+{
+ const char stop_type = stop_packet.GetChar();
+ switch (stop_type)
+ {
+ case 'T':
+ case 'S':
+ {
+ // Stop with signal and thread info
+ const uint8_t signo = stop_packet.GetHexU8();
+ std::string name;
+ std::string value;
+ std::string thread_name;
+ uint32_t exc_type = 0;
+ std::vector<uint64_t> exc_data;
+ uint32_t tid = LLDB_INVALID_THREAD_ID;
+ addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
+ uint32_t exc_data_count = 0;
+ 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("mecount") == 0)
+ {
+ // exception count in big endian hex
+ exc_data_count = 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
+ tid = Args::StringToUInt32 (value.c_str(), 0, 16);
+ }
+ else if (name.compare("name") == 0)
+ {
+ thread_name.swap (value);
+ }
+ else if (name.compare("dispatchqaddr") == 0)
+ {
+ thread_dispatch_qaddr = Args::StringToUInt64 (value.c_str(), 0, 16);
+ }
+ }
+ ThreadSP thread_sp (m_thread_list.FindThreadByID(tid, false));
+
+ if (thread_sp)
+ {
+ ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get());
+
+ gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr);
+ gdb_thread->SetName (thread_name.empty() ? thread_name.c_str() : NULL);
+ Thread::StopInfo& stop_info = gdb_thread->GetStopInfoRef();
+ gdb_thread->SetStopInfoStopID (GetStopID());
+ if (exc_type != 0)
+ {
+ if (exc_type == EXC_SOFTWARE && exc_data.size() == 2 && exc_data[0] == EXC_SOFT_SIGNAL)
+ {
+ stop_info.SetStopReasonWithSignal(exc_data[1]);
+ }
+#if defined (MACH_EXC_DATA0_SOFTWARE_BREAKPOINT)
+ else if (exc_type == EXC_BREAKPOINT && exc_data[0] == MACH_EXC_DATA0_SOFTWARE_BREAKPOINT)
+ {
+ addr_t pc = gdb_thread->GetRegisterContext()->GetPC();
+ user_id_t break_id = GetBreakpointSiteList().FindIDByAddress(pc);
+ if (break_id == LLDB_INVALID_BREAK_ID)
+ {
+ //log->Printf("got EXC_BREAKPOINT at 0x%llx but didn't find a breakpoint site.\n", pc);
+ stop_info.SetStopReasonWithException(exc_type, exc_data.size());
+ for (uint32_t i=0; i<exc_data.size(); ++i)
+ stop_info.SetExceptionDataAtIndex(i, exc_data[i]);
+ }
+ else
+ {
+ stop_info.Clear ();
+ stop_info.SetStopReasonWithBreakpointSiteID (break_id);
+ }
+ }
+#endif
+#if defined (MACH_EXC_DATA0_TRACE)
+ else if (exc_type == EXC_BREAKPOINT && exc_data[0] == MACH_EXC_DATA0_TRACE)
+ {
+ stop_info.SetStopReasonToTrace ();
+ }
+#endif
+ else
+ {
+ stop_info.SetStopReasonWithException(exc_type, exc_data.size());
+ for (uint32_t i=0; i<exc_data.size(); ++i)
+ stop_info.SetExceptionDataAtIndex(i, exc_data[i]);
+ }
+ }
+ else if (signo)
+ {
+ stop_info.SetStopReasonWithSignal(signo);
+ }
+ else
+ {
+ stop_info.SetStopReasonToNone();
+ }
+ }
+ return eStateStopped;
+ }
+ break;
+
+ case 'W':
+ // process exited
+ return eStateExited;
+
+ default:
+ break;
+ }
+ return eStateInvalid;
+}
+
+void
+ProcessGDBRemote::RefreshStateAfterStop ()
+{
+ // We must be attaching if we don't already have a valid architecture
+ if (!m_arch_spec.IsValid())
+ {
+ Module *exe_module = GetTarget().GetExecutableModule().get();
+ if (exe_module)
+ m_arch_spec = exe_module->GetArchitecture();
+ }
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ m_thread_list.RefreshStateAfterStop();
+
+ // Discover new threads:
+ UpdateThreadListIfNeeded ();
+}
+
+Error
+ProcessGDBRemote::DoHalt ()
+{
+ Error error;
+ if (m_gdb_comm.IsRunning())
+ {
+ bool timed_out = false;
+ if (!m_gdb_comm.SendInterrupt (2, &timed_out))
+ {
+ if (timed_out)
+ error.SetErrorString("timed out sending interrupt packet");
+ else
+ error.SetErrorString("unknown error sending interrupt packet");
+ }
+ }
+ return error;
+}
+
+Error
+ProcessGDBRemote::WillDetach ()
+{
+ Error error;
+ const StateType state = m_private_state.GetValue();
+
+ if (IsRunning(state))
+ error.SetErrorString("Process must be stopped in order to detach.");
+
+ return error;
+}
+
+
+Error
+ProcessGDBRemote::DoDestroy ()
+{
+ Error error;
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy()");
+
+ // Interrupt if our inferior is running...
+ m_gdb_comm.SendInterrupt (1);
+ DisableAllBreakpointSites ();
+ SetExitStatus(-1, "process killed");
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse("k", response, 2, false))
+ {
+ if (log)
+ {
+ if (response.IsOKPacket())
+ log->Printf ("ProcessGDBRemote::DoDestroy() kill was successful");
+ else
+ log->Printf ("ProcessGDBRemote::DoDestroy() kill failed: %s", response.GetStringRef().c_str());
+ }
+ }
+
+ StopAsyncThread ();
+ m_gdb_comm.StopReadThread();
+ KillDebugserverProcess ();
+ return error;
+}
+
+ByteOrder
+ProcessGDBRemote::GetByteOrder () const
+{
+ return m_byte_order;
+}
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessGDBRemote::IsAlive ()
+{
+ return m_gdb_comm.IsConnected();
+}
+
+addr_t
+ProcessGDBRemote::GetImageInfoAddress()
+{
+ if (!m_gdb_comm.IsRunning())
+ {
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, 2, false))
+ {
+ if (response.IsNormalPacket())
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+DynamicLoader *
+ProcessGDBRemote::GetDynamicLoader()
+{
+ return m_dynamic_loader_ap.get();
+}
+
+//------------------------------------------------------------------
+// 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%llx,%zx", (uint64_t)addr, size);
+ assert (packet_len + 1 < sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 2, true))
+ {
+ if (response.IsNormalPacket())
+ {
+ error.Clear();
+ return response.GetHexBytes(buf, size, '\xdd');
+ }
+ else if (response.IsErrorPacket())
+ error.SetErrorStringWithFormat("gdb remote returned an error: %s", response.GetStringRef().c_str());
+ else if (response.IsUnsupportedPacket())
+ error.SetErrorStringWithFormat("'%s' packet unsupported", packet);
+ else
+ error.SetErrorStringWithFormat("unexpected response to '%s': '%s'", packet, response.GetStringRef().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("failed to sent packet: '%s'", packet);
+ }
+ return 0;
+}
+
+size_t
+ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
+{
+ StreamString packet;
+ packet.Printf("M%llx,%zx:", addr, size);
+ packet.PutBytesAsRawHex8(buf, size, eByteOrderHost, eByteOrderHost);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, 2, true))
+ {
+ if (response.IsOKPacket())
+ {
+ error.Clear();
+ return size;
+ }
+ else if (response.IsErrorPacket())
+ error.SetErrorStringWithFormat("gdb remote returned an error: %s", response.GetStringRef().c_str());
+ else if (response.IsUnsupportedPacket())
+ error.SetErrorStringWithFormat("'%s' packet unsupported", packet.GetString().c_str());
+ else
+ error.SetErrorStringWithFormat("unexpected response to '%s': '%s'", packet.GetString().c_str(), response.GetStringRef().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("failed to sent 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 = m_gdb_comm.AllocateMemory (size, permissions, m_packet_timeout);
+ if (allocated_addr == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %u", size, permissions);
+ else
+ error.Clear();
+ return allocated_addr;
+}
+
+Error
+ProcessGDBRemote::DoDeallocateMemory (lldb::addr_t addr)
+{
+ Error error;
+ if (!m_gdb_comm.DeallocateMemory (addr, m_packet_timeout))
+ error.SetErrorStringWithFormat("unable to deallocate memory at 0x%llx", addr);
+ return error;
+}
+
+
+//------------------------------------------------------------------
+// Process STDIO
+//------------------------------------------------------------------
+
+size_t
+ProcessGDBRemote::GetSTDOUT (char *buf, size_t buf_size, Error &error)
+{
+ Mutex::Locker locker(m_stdio_mutex);
+ size_t bytes_available = m_stdout_data.size();
+ if (bytes_available > 0)
+ {
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PROCESS, "ProcessGDBRemote::%s (&%p[%u]) ...", __FUNCTION__, buf, buf_size);
+ if (bytes_available > buf_size)
+ {
+ memcpy(buf, m_stdout_data.data(), buf_size);
+ m_stdout_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ }
+ else
+ {
+ memcpy(buf, m_stdout_data.data(), bytes_available);
+ m_stdout_data.clear();
+
+ //ResetEventBits(eBroadcastBitSTDOUT);
+ }
+ }
+ return bytes_available;
+}
+
+size_t
+ProcessGDBRemote::GetSTDERR (char *buf, size_t buf_size, Error &error)
+{
+ // Can we get STDERR through the remote protocol?
+ return 0;
+}
+
+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::EnableBreakpoint (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::EnableBreakpoint (size_id = %d) address = 0x%llx", site_id, (uint64_t)addr);
+
+ if (bp_site->IsEnabled())
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::EnableBreakpoint (size_id = %d) address = 0x%llx -- 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_z0_supported)
+ {
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "Z0,%llx,%zx", addr, bp_op_size);
+ assert (packet_len + 1 < sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 2, true))
+ {
+ if (response.IsUnsupportedPacket())
+ {
+ // Disable z packet support and try again
+ m_z0_supported = 0;
+ return EnableBreakpoint (bp_site);
+ }
+ else if (response.IsOKPacket())
+ {
+ bp_site->SetEnabled(true);
+ bp_site->SetType (BreakpointSite::eExternal);
+ return error;
+ }
+ else
+ {
+ uint8_t error_byte = response.GetError();
+ if (error_byte)
+ error.SetErrorStringWithFormat("%x packet failed with error: %i (0x%2.2x).\n", packet, error_byte, error_byte);
+ }
+ }
+ }
+ else
+ {
+ return EnableSoftwareBreakpoint (bp_site);
+ }
+ }
+
+ if (log)
+ {
+ const char *err_string = error.AsCString();
+ log->Printf ("ProcessGDBRemote::EnableBreakpoint() error for breakpoint at 0x%8.8llx: %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::DisableBreakpoint (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::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx", site_id, (uint64_t)addr);
+
+ if (bp_site->IsEnabled())
+ {
+ const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site);
+
+ if (bp_site->IsHardware())
+ {
+ // TODO: disable hardware breakpoint...
+ }
+ else
+ {
+ if (m_z0_supported)
+ {
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "z0,%llx,%zx", addr, bp_op_size);
+ assert (packet_len + 1 < sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 2, true))
+ {
+ if (response.IsUnsupportedPacket())
+ {
+ error.SetErrorString("Breakpoint site was set with Z packet, yet remote debugserver states z packets are not supported.");
+ }
+ else if (response.IsOKPacket())
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx -- SUCCESS", site_id, (uint64_t)addr);
+ bp_site->SetEnabled(false);
+ return error;
+ }
+ else
+ {
+ uint8_t error_byte = response.GetError();
+ if (error_byte)
+ error.SetErrorStringWithFormat("%x packet failed with error: %i (0x%2.2x).\n", packet, error_byte, error_byte);
+ }
+ }
+ }
+ else
+ {
+ return DisableSoftwareBreakpoint (bp_site);
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx -- SUCCESS (already disabled)", site_id, (uint64_t)addr);
+ return error;
+ }
+
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+Error
+ProcessGDBRemote::EnableWatchpoint (WatchpointLocation *wp)
+{
+ 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 = %d)", watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessGDBRemote::EnableWatchpoint(watchID = %d) addr = 0x%8.8llx: watchpoint already enabled.", watchID, (uint64_t)addr);
+ return error;
+ }
+ else
+ {
+ // Pass down an appropriate z/Z packet...
+ error.SetErrorString("watchpoints not supported");
+ }
+ }
+ else
+ {
+ error.SetErrorString("Watchpoint location argument was NULL.");
+ }
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+Error
+ProcessGDBRemote::DisableWatchpoint (WatchpointLocation *wp)
+{
+ 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 = %d) addr = 0x%8.8llx", watchID, (uint64_t)addr);
+
+ if (wp->IsHardware())
+ {
+ // Pass down an appropriate z/Z packet...
+ error.SetErrorString("watchpoints not supported");
+ }
+ // TODO: clear software watchpoints if we implement them
+ }
+ else
+ {
+ error.SetErrorString("Watchpoint location argument was NULL.");
+ }
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+void
+ProcessGDBRemote::Clear()
+{
+ m_flags = 0;
+ m_thread_list.Clear();
+ {
+ Mutex::Locker locker(m_stdio_mutex);
+ m_stdout_data.clear();
+ }
+ DestoryLibUnwindAddressSpace();
+}
+
+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::DoDetach()
+{
+ Error error;
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDetach()");
+
+ // if (DoSIGSTOP (true))
+ // {
+ // CloseChildFileDescriptors ();
+ //
+ // // Scope for "locker" so we can reply to all of our exceptions (the SIGSTOP
+ // // exception).
+ // {
+ // Mutex::Locker locker(m_exception_messages_mutex);
+ // ReplyToAllExceptions();
+ // }
+ //
+ // // Shut down the exception thread and cleanup our exception remappings
+ // Task().ShutDownExceptionThread();
+ //
+ // pid_t pid = GetID();
+ //
+ // // Detach from our process while we are stopped.
+ // errno = 0;
+ //
+ // // Detach from our process
+ // ::ptrace (PT_DETACH, pid, (caddr_t)1, 0);
+ //
+ // error.SetErrorToErrno();
+ //
+ // if (log || error.Fail())
+ // error.PutToLog(log, "::ptrace (PT_DETACH, %u, (caddr_t)1, 0)", pid);
+ //
+ // // Resume our task
+ // Task().Resume();
+ //
+ // // NULL our task out as we have already retored all exception ports
+ // Task().Clear();
+ //
+ // // Clear out any notion of the process we once were
+ // Clear();
+ //
+ // SetPrivateState (eStateDetached);
+ // return true;
+ // }
+ return error;
+}
+
+void
+ProcessGDBRemote::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len)
+{
+ ProcessGDBRemote *process = (ProcessGDBRemote *)baton;
+ process->AppendSTDOUT(static_cast<const char *>(src), src_len);
+}
+
+void
+ProcessGDBRemote::AppendSTDOUT (const char* s, size_t len)
+{
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PROCESS, "ProcessGDBRemote::%s (<%d> %s) ...", __FUNCTION__, len, s);
+ Mutex::Locker locker(m_stdio_mutex);
+ m_stdout_data.append(s, len);
+
+ // FIXME: Make a real data object for this and put it out.
+ BroadcastEventIfUnique (eBroadcastBitSTDOUT);
+}
+
+
+Error
+ProcessGDBRemote::StartDebugserverProcess
+(
+ const char *debugserver_url, // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...")
+ char const *inferior_argv[], // Arguments for the inferior program including the path to the inferior itself as the first argument
+ char const *inferior_envp[], // Environment to pass along to the inferior program
+ char const *stdio_path,
+ lldb::pid_t attach_pid, // If inferior inferior_argv == NULL, and attach_pid != LLDB_INVALID_PROCESS_ID then attach to this attach_pid
+ const char *attach_name, // Wait for the next process to launch whose basename matches "attach_name"
+ bool wait_for_launch, // Wait for the process named "attach_name" to launch
+ ArchSpec& inferior_arch // The arch of the inferior that we will launch
+)
+{
+ 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;
+
+ FileSpec debugserver_file_spec;
+ char debugserver_path[PATH_MAX];
+
+ // 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);
+ 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.
+ FileSpec framework_file_spec (Host::GetModuleFileSpecForHostAddress ((void *)lldb_private::Initialize));
+ const char *framework_dir = framework_file_spec.GetDirectory().AsCString();
+ const char *lldb_framework = ::strstr (framework_dir, "/LLDB.framework");
+
+ if (lldb_framework)
+ {
+ int len = lldb_framework - framework_dir + strlen ("/LLDB.framework");
+ ::snprintf (debugserver_path,
+ sizeof(debugserver_path),
+ "%.*s/Resources/%s",
+ len,
+ framework_dir,
+ DEBUGSERVER_BASENAME);
+ debugserver_file_spec.SetFile (debugserver_path);
+ 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();
+ posix_spawnattr_t attr;
+
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS);
+
+ Error local_err; // Errors that don't affect the spawning.
+ if (log)
+ log->Printf ("%s ( path='%s', argv=%p, envp=%p, arch=%s )", __FUNCTION__, debugserver_path, inferior_argv, inferior_envp, inferior_arch.AsCString());
+ error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX);
+ if (error.Fail() || log)
+ error.PutToLog(log, "::posix_spawnattr_init ( &attr )");
+ if (error.Fail())
+ return error;;
+
+#if !defined (__arm__)
+
+ // We don't need to do this for ARM, and we really shouldn't now that we
+ // have multiple CPU subtypes and no posix_spawnattr call that allows us
+ // to set which CPU subtype to launch...
+ cpu_type_t cpu = inferior_arch.GetCPUType();
+ if (cpu != 0 && cpu != CPU_TYPE_ANY && cpu != LLDB_INVALID_CPUTYPE)
+ {
+ size_t ocount = 0;
+ error.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX);
+ if (error.Fail() || log)
+ error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %zu )", cpu, ocount);
+
+ if (error.Fail() != 0 || ocount != 1)
+ return error;
+ }
+
+#endif
+
+ Args debugserver_args;
+ char arg_cstr[PATH_MAX];
+ bool launch_process = true;
+
+ if (inferior_argv == NULL && attach_pid != LLDB_INVALID_PROCESS_ID)
+ launch_process = false;
+ else if (attach_name)
+ launch_process = false; // Wait for a process whose basename matches that in inferior_argv[0]
+
+ bool pass_stdio_path_to_debugserver = true;
+ lldb_utility::PseudoTerminal pty;
+ if (stdio_path == NULL)
+ {
+ pass_stdio_path_to_debugserver = false;
+ if (pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, NULL, 0))
+ {
+ struct termios stdin_termios;
+ if (::tcgetattr (pty.GetMasterFileDescriptor(), &stdin_termios) == 0)
+ {
+ stdin_termios.c_lflag &= ~ECHO; // Turn off echoing
+ stdin_termios.c_lflag &= ~ICANON; // Get one char at a time
+ ::tcsetattr (pty.GetMasterFileDescriptor(), TCSANOW, &stdin_termios);
+ }
+ stdio_path = pty.GetSlaveName (NULL, 0);
+ }
+ }
+
+ // Start args with "debugserver /file/path -r --"
+ debugserver_args.AppendArgument(debugserver_path);
+ debugserver_args.AppendArgument(debugserver_url);
+ debugserver_args.AppendArgument("--native-regs"); // use native registers, not the GDB registers
+ debugserver_args.AppendArgument("--setsid"); // make debugserver run in its own session so
+ // signals generated by special terminal key
+ // sequences (^C) don't affect debugserver
+
+ // Only set the inferior
+ if (launch_process)
+ {
+ if (stdio_path && pass_stdio_path_to_debugserver)
+ {
+ debugserver_args.AppendArgument("-s"); // short for --stdio-path
+ StreamString strm;
+ strm.Printf("'%s'", stdio_path);
+ debugserver_args.AppendArgument(strm.GetData()); // path to file to have inferior open as it's STDIO
+ }
+ }
+
+ 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=0x800e0e");
+
+ // Now append the program arguments
+ if (launch_process)
+ {
+ 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
+ {
+ // Will send environment entries with the 'QEnvironment:' packet
+ // Will send arguments with the 'A' packet
+ }
+ }
+ 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);
+ }
+
+ Error file_actions_err;
+ posix_spawn_file_actions_t file_actions;
+#if DONT_CLOSE_DEBUGSERVER_STDIO
+ file_actions_err.SetErrorString ("Remove this after uncommenting the code block below.");
+#else
+ file_actions_err.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX);
+ if (file_actions_err.Success())
+ {
+ ::posix_spawn_file_actions_addclose (&file_actions, STDIN_FILENO);
+ ::posix_spawn_file_actions_addclose (&file_actions, STDOUT_FILENO);
+ ::posix_spawn_file_actions_addclose (&file_actions, STDERR_FILENO);
+ }
+#endif
+
+ if (log)
+ {
+ StreamString strm;
+ debugserver_args.Dump (&strm);
+ log->Printf("%s arguments:\n%s", debugserver_args.GetArgumentAtIndex(0), strm.GetData());
+ }
+
+ error.SetError(::posix_spawnp (&m_debugserver_pid,
+ debugserver_path,
+ file_actions_err.Success() ? &file_actions : NULL,
+ &attr,
+ debugserver_args.GetArgumentVector(),
+ (char * const*)inferior_envp),
+ eErrorTypePOSIX);
+
+ if (file_actions_err.Success())
+ ::posix_spawn_file_actions_destroy (&file_actions);
+
+ // We have seen some cases where posix_spawnp was returning a valid
+ // looking pid even when an error was returned, so clear it out
+ if (error.Fail())
+ m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+
+ if (error.Fail() || log)
+ error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", m_debugserver_pid, debugserver_path, NULL, &attr, inferior_argv, inferior_envp);
+
+// if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+// {
+// std::auto_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor (pty.ReleaseMasterFileDescriptor(), 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();
+// }
+// }
+// }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Unable to locate " DEBUGSERVER_BASENAME ".\n");
+ }
+
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ StartAsyncThread ();
+ }
+ return error;
+}
+
+bool
+ProcessGDBRemote::MonitorDebugserverProcess
+(
+ void *callback_baton,
+ lldb::pid_t debugserver_pid,
+ int signo, // Zero for no signal
+ int exit_status // Exit value of process if signal is zero
+)
+{
+ // We pass in the ProcessGDBRemote inferior process it and name it
+ // "gdb_remote_pid". The process ID is passed in the "callback_baton"
+ // pointer value itself, thus we need the double cast...
+
+ // "debugserver_pid" argument passed in is the process ID for
+ // debugserver that we are tracking...
+
+ lldb::pid_t gdb_remote_pid = (lldb::pid_t)(intptr_t)callback_baton;
+ TargetSP target_sp(Debugger::GetSharedInstance().GetTargetList().FindTargetWithProcessID (gdb_remote_pid));
+ if (target_sp)
+ {
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ {
+ // 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.
+ if (process_sp->GetState() != eStateExited)
+ {
+ char error_str[1024];
+ if (signo)
+ {
+ const char *signal_cstr = process_sp->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_sp->SetExitStatus (-1, error_str);
+ }
+ else
+ {
+ ProcessGDBRemote *gdb_process = (ProcessGDBRemote *)process_sp.get();
+ // Debugserver has exited we need to let our ProcessGDBRemote
+ // know that it no longer has a debugserver instance
+ gdb_process->m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+ // We are returning true to this function below, so we can
+ // forget about the monitor handle.
+ gdb_process->m_debugserver_monitor = 0;
+ }
+ }
+ }
+ 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);
+
+ Log::Callbacks log_callbacks = {
+ ProcessGDBRemoteLog::DisableLog,
+ ProcessGDBRemoteLog::EnableLog,
+ ProcessGDBRemoteLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessGDBRemote::GetPluginNameStatic(), log_callbacks);
+ }
+}
+
+bool
+ProcessGDBRemote::SetCurrentGDBRemoteThread (int tid)
+{
+ if (m_curr_tid == tid)
+ return true;
+
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "Hg%x", tid);
+ assert (packet_len + 1 < sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 2, false))
+ {
+ if (response.IsOKPacket())
+ {
+ m_curr_tid = tid;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+ProcessGDBRemote::SetCurrentGDBRemoteThreadForRun (int tid)
+{
+ if (m_curr_tid_run == tid)
+ return true;
+
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "Hg%x", tid);
+ assert (packet_len + 1 < sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 2, false))
+ {
+ if (response.IsOKPacket())
+ {
+ m_curr_tid_run = tid;
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+ProcessGDBRemote::ResetGDBRemoteState ()
+{
+ // Reset and GDB remote state
+ m_curr_tid = LLDB_INVALID_THREAD_ID;
+ m_curr_tid_run = LLDB_INVALID_THREAD_ID;
+ m_z0_supported = 1;
+}
+
+
+bool
+ProcessGDBRemote::StartAsyncThread ()
+{
+ ResetGDBRemoteState ();
+
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
+
+ // 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);
+ return m_async_thread != LLDB_INVALID_HOST_THREAD;
+}
+
+void
+ProcessGDBRemote::StopAsyncThread ()
+{
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
+
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit);
+
+ // Stop the stdio thread
+ if (m_async_thread != LLDB_INVALID_HOST_THREAD)
+ {
+ Host::ThreadJoin (m_async_thread, NULL, NULL);
+ }
+}
+
+
+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 = %i) 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)
+ {
+ bool done = false;
+ while (!done)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) listener.WaitForEvent (NULL, event_sp)...", __FUNCTION__, arg, process->GetID());
+ if (listener.WaitForEvent (NULL, event_sp))
+ {
+ const uint32_t event_type = event_sp->GetType();
+ 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 = %i) got eBroadcastBitAsyncContinue: %s", __FUNCTION__, arg, process->GetID(), continue_cstr);
+
+ process->SetPrivateState(eStateRunning);
+ StringExtractorGDBRemote response;
+ StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response);
+
+ switch (stop_state)
+ {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ process->m_last_stop_packet = response;
+ process->m_last_stop_packet.SetFilePos (0);
+ process->SetPrivateState (stop_state);
+ break;
+
+ case eStateExited:
+ process->m_last_stop_packet = response;
+ process->m_last_stop_packet.SetFilePos (0);
+ response.SetFilePos(1);
+ process->SetExitStatus(response.GetHexU8(), NULL);
+ done = true;
+ break;
+
+ case eStateInvalid:
+ break;
+
+ default:
+ process->SetPrivateState (stop_state);
+ break;
+ }
+ }
+ }
+ break;
+
+ case eBroadcastBitAsyncThreadShouldExit:
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) got eBroadcastBitAsyncThreadShouldExit...", __FUNCTION__, arg, process->GetID());
+ done = true;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type);
+ done = true;
+ break;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) listener.WaitForEvent (NULL, event_sp) => false", __FUNCTION__, arg, process->GetID());
+ done = true;
+ }
+ }
+ }
+
+ 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;
+}
+
+lldb_private::unw_addr_space_t
+ProcessGDBRemote::GetLibUnwindAddressSpace ()
+{
+ unw_targettype_t target_type = UNW_TARGET_UNSPECIFIED;
+ if (m_target.GetArchitecture().GetCPUType() == CPU_TYPE_I386)
+ target_type = UNW_TARGET_I386;
+ if (m_target.GetArchitecture().GetCPUType() == CPU_TYPE_X86_64)
+ target_type = UNW_TARGET_X86_64;
+
+ if (m_libunwind_addr_space)
+ {
+ if (m_libunwind_target_type != target_type)
+ DestoryLibUnwindAddressSpace();
+ else
+ return m_libunwind_addr_space;
+ }
+ unw_accessors_t callbacks = get_macosx_libunwind_callbacks ();
+ m_libunwind_addr_space = unw_create_addr_space (&callbacks, target_type);
+ if (m_libunwind_addr_space)
+ m_libunwind_target_type = target_type;
+ else
+ m_libunwind_target_type = UNW_TARGET_UNSPECIFIED;
+ return m_libunwind_addr_space;
+}
+
+void
+ProcessGDBRemote::DestoryLibUnwindAddressSpace ()
+{
+ if (m_libunwind_addr_space)
+ {
+ unw_destroy_addr_space (m_libunwind_addr_space);
+ m_libunwind_addr_space = NULL;
+ }
+ m_libunwind_target_type = UNW_TARGET_UNSPECIFIED;
+}
+
+
+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)
+ {
+ ModuleSP module_sp(GetTarget().GetImages().FindFirstModuleForFileSpec (FileSpec("libSystem.B.dylib")));
+ if (module_sp.get() == NULL)
+ return NULL;
+
+ const Symbol *dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (ConstString("dispatch_queue_offsets"), eSymbolTypeData);
+ if (dispatch_queue_offsets_symbol)
+ m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetValue().GetLoadAddress(this);
+
+ if (m_dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
+ return NULL;
+ }
+
+ uint8_t memory_buffer[8];
+ DataExtractor data(memory_buffer, sizeof(memory_buffer), GetByteOrder(), GetAddressByteSize());
+
+ // Excerpt from src/queue_private.h
+ struct dispatch_queue_offsets_s
+ {
+ uint16_t dqo_version;
+ uint16_t dqo_label;
+ uint16_t dqo_label_size;
+ } dispatch_queue_offsets;
+
+
+ Error error;
+ if (ReadMemory (m_dispatch_queue_offsets_addr, memory_buffer, sizeof(dispatch_queue_offsets), error) == sizeof(dispatch_queue_offsets))
+ {
+ uint32_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);
+ 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();
+}
+
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
new file mode 100644
index 00000000000..cd5bab0194f
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -0,0 +1,404 @@
+//===-- 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>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+#include "GDBRemoteCommunication.h"
+#include "StringExtractor.h"
+#include "GDBRemoteRegisterContext.h"
+#include "libunwind.h"
+
+class ThreadGDBRemote;
+
+class ProcessGDBRemote : public lldb_private::Process
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ static Process*
+ CreateInstance (lldb_private::Target& target, lldb_private::Listener &listener);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ 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);
+
+ //------------------------------------------------------------------
+ // 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* module,
+ char const *argv[], // Can be NULL
+ char const *envp[], // Can be NULL
+ const char *stdin_path, // Can be NULL
+ const char *stdout_path, // Can be NULL
+ const char *stderr_path); // Can be NULL
+
+ virtual void
+ DidLaunch ();
+
+ virtual lldb_private::Error
+ WillAttach (lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ WillAttach (const char *process_name, bool wait_for_launch);
+
+ lldb_private::Error
+ WillLaunchOrAttach ();
+
+ virtual lldb_private::Error
+ DoAttach (lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ DoAttach (const char *process_name, bool wait_for_launch);
+
+ virtual void
+ DidAttach ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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);
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ WillResume ();
+
+ virtual lldb_private::Error
+ DoResume ();
+
+ virtual lldb_private::Error
+ DoHalt ();
+
+ virtual lldb_private::Error
+ WillDetach ();
+
+ virtual lldb_private::Error
+ DoDetach ();
+
+ 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
+ DoDeallocateMemory (lldb::addr_t ptr);
+
+ //------------------------------------------------------------------
+ // Process STDIO
+ //------------------------------------------------------------------
+ virtual size_t
+ GetSTDOUT (char *buf, size_t buf_size, lldb_private::Error &error);
+
+ virtual size_t
+ GetSTDERR (char *buf, size_t buf_size, lldb_private::Error &error);
+
+ virtual size_t
+ PutSTDIN (const char *buf, size_t buf_size, lldb_private::Error &error);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode (lldb_private::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableBreakpoint (lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ DisableBreakpoint (lldb_private::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Watchpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableWatchpoint (lldb_private::WatchpointLocation *wp_loc);
+
+ virtual lldb_private::Error
+ DisableWatchpoint (lldb_private::WatchpointLocation *wp_loc);
+
+ virtual lldb::ByteOrder
+ GetByteOrder () const;
+
+ virtual lldb_private::DynamicLoader *
+ GetDynamicLoader ();
+
+protected:
+ friend class ThreadGDBRemote;
+ friend class GDBRemoteCommunication;
+ friend class GDBRemoteRegisterContext;
+
+ bool
+ SetCurrentGDBRemoteThread (int tid);
+
+ bool
+ SetCurrentGDBRemoteThreadForRun (int tid);
+
+ //----------------------------------------------------------------------
+ // 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;
+
+ static void
+ STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
+
+ void
+ AppendSTDOUT (const char* s, size_t len);
+
+ lldb_private::ArchSpec&
+ GetArchSpec()
+ {
+ return m_arch_spec;
+ }
+ const lldb_private::ArchSpec&
+ GetArchSpec() const
+ {
+ return m_arch_spec;
+ }
+
+ void
+ Clear ( );
+
+ lldb_private::Flags &
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const lldb_private::Flags &
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ uint32_t
+ UpdateThreadListIfNeeded ();
+
+ lldb_private::Error
+ StartDebugserverProcess (const char *debugserver_url, // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...")
+ char const *inferior_argv[],
+ char const *inferior_envp[],
+ const char *stdin_path,
+ lldb::pid_t attach_pid, // If inferior inferior_argv == NULL, then attach to this pid
+ const char *attach_pid_name, // Wait for the next process to launch whose basename matches "attach_wait_name"
+ bool wait_for_launch, // Wait for the process named "attach_wait_name" to launch
+ lldb_private::ArchSpec& arch_spec);
+
+ void
+ KillDebugserverProcess ();
+
+ void
+ BuildDynamicRegisterInfo ();
+
+ GDBRemoteCommunication &
+ GetGDBRemote()
+ {
+ return m_gdb_comm;
+ }
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitAsyncContinue = (1 << 0),
+ eBroadcastBitAsyncThreadShouldExit = (1 << 1)
+ };
+
+
+ std::auto_ptr<lldb_private::DynamicLoader> m_dynamic_loader_ap;
+ lldb_private::Flags m_flags; // Process specific flags (see eFlags enums)
+ lldb_private::Communication m_stdio_communication;
+ lldb_private::Mutex m_stdio_mutex; // Multithreaded protection for stdio
+ std::string m_stdout_data;
+ lldb_private::ArchSpec m_arch_spec;
+ lldb::ByteOrder m_byte_order;
+ GDBRemoteCommunication m_gdb_comm;
+ lldb::pid_t m_debugserver_pid;
+ uint32_t m_debugserver_monitor;
+ StringExtractor m_last_stop_packet;
+ GDBRemoteDynamicRegisterInfo m_register_info;
+ lldb_private::Broadcaster m_async_broadcaster;
+ lldb::thread_t m_async_thread;
+ // Current GDB remote state. Any members added here need to be reset to
+ // proper default values in ResetGDBRemoteState ().
+ 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_z0_supported:1; // Set to non-zero if Z0 and z0 packets are supported
+ lldb_private::StreamString m_continue_packet;
+ lldb::addr_t m_dispatch_queue_offsets_addr;
+ uint32_t m_packet_timeout;
+ size_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory
+ lldb_private::unw_targettype_t m_libunwind_target_type;
+ lldb_private::unw_addr_space_t m_libunwind_addr_space; // libunwind address space object for this process.
+ bool m_waiting_for_attach;
+
+ void
+ ResetGDBRemoteState ();
+
+ bool
+ StartAsyncThread ();
+
+ void
+ StopAsyncThread ();
+
+ static void *
+ AsyncThread (void *arg);
+
+ static bool
+ MonitorDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ int signo, // Zero for no signal
+ int exit_status); // Exit value of process if signal is zero
+
+ lldb::StateType
+ SetThreadStopInfo (StringExtractor& stop_packet);
+
+ 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);
+
+private:
+ //------------------------------------------------------------------
+ // For ProcessGDBRemote only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ProcessGDBRemote);
+
+ lldb_private::unw_addr_space_t
+ GetLibUnwindAddressSpace ();
+
+ void
+ DestoryLibUnwindAddressSpace ();
+};
+
+#endif // liblldb_ProcessGDBRemote_h_
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
new file mode 100644
index 00000000000..051ce8f20f4
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
@@ -0,0 +1,121 @@
+//===-- 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/Core/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static Log* g_log = NULL; // Leak for now as auto_ptr was being cleaned up
+ // by global constructors before other threads
+ // were done with it.
+Log *
+ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log = g_log;
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().GetAllFlagBits();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+void
+ProcessGDBRemoteLog::DisableLog ()
+{
+ if (g_log)
+ {
+ delete g_log;
+ g_log = NULL;
+ }
+}
+
+Log *
+ProcessGDBRemoteLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, Args &args, Stream *feedback_strm)
+{
+ DisableLog ();
+ g_log = new Log (log_stream_sp);
+ if (g_log)
+ {
+ uint32_t flag_bits = 0;
+ bool got_unknown_category = false;
+ const size_t argc = args.GetArgumentCount();
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *arg = args.GetArgumentAtIndex(i);
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits |= GDBR_LOG_ALL;
+ else if (::strcasestr (arg, "break") == arg ) flag_bits |= GDBR_LOG_BREAKPOINTS;
+ 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 (::strcasestr (arg, "watch") == arg ) 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().SetAllFlagBits(flag_bits);
+ g_log->GetOptions().SetAllFlagBits(log_options);
+ }
+ return g_log;
+}
+
+void
+ProcessGDBRemoteLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf("Logging categories for '%s':\n"
+ "\tall - turn on all available logging categories\n"
+ "\tbreak - log breakpoints\n"
+ "\tdefault - enable the default set of logging categories for liblldb\n"
+ "\tpackets - log gdb remote packets\n"
+ "\tmemory - log memory reads and writes\n"
+ "\tdata-short - log memory bytes for memory reads and writes for short transactions only\n"
+ "\tdata-long - log memory bytes for memory reads and writes for all transactions\n"
+ "\tprocess - log process events and activities\n"
+ "\tthread - log thread events and activities\n"
+ "\tstep - log step related activities\n"
+ "\tverbose - enable verbose loggging\n"
+ "\twatch - log watchpoint related activities\n", ProcessGDBRemote::GetPluginNameStatic());
+}
+
+
+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/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
new file mode 100644
index 00000000000..97580d38674
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
@@ -0,0 +1,53 @@
+//===-- 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_ALL (UINT32_MAX)
+#define GDBR_LOG_DEFAULT GDBR_LOG_PACKETS
+
+class ProcessGDBRemoteLog
+{
+public:
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static void
+ DisableLog ();
+
+ static lldb_private::Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, lldb_private::Args &args, 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/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
new file mode 100644
index 00000000000..37485edf4e5
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
@@ -0,0 +1,296 @@
+//===-- 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/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Breakpoint/WatchpointLocation.h"
+
+#include "LibUnwindRegisterContext.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "StringExtractorGDBRemote.h"
+#include "UnwindLibUnwind.h"
+#include "UnwindMacOSXFrameBackchain.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Thread Registers
+//----------------------------------------------------------------------
+
+ThreadGDBRemote::ThreadGDBRemote (ProcessGDBRemote &process, lldb::tid_t tid) :
+ Thread(process, tid),
+ m_stop_info_stop_id (0),
+ m_stop_info (this),
+ m_thread_name (),
+ m_dispatch_queue_name (),
+ m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS),
+ m_unwinder_ap ()
+{
+// ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD | GDBR_LOG_VERBOSE, "ThreadGDBRemote::ThreadGDBRemote ( pid = %i, tid = 0x%4.4x, )", m_process.GetID(), GetID());
+ ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this, m_process.GetID(), GetID());
+}
+
+ThreadGDBRemote::~ThreadGDBRemote ()
+{
+ ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::~ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this, m_process.GetID(), GetID());
+}
+
+
+const char *
+ThreadGDBRemote::GetInfo ()
+{
+ return NULL;
+}
+
+
+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)
+ return GetGDBProcess().GetDispatchQueueNameForThread (m_thread_dispatch_qaddr, m_dispatch_queue_name);
+ return NULL;
+}
+
+bool
+ThreadGDBRemote::WillResume (StateType resume_state)
+{
+ // TODO: cache for next time in case we can match things up??
+ ClearStackFrames();
+ int signo = GetResumeSignal();
+ m_stop_info.Clear();
+ switch (resume_state)
+ {
+ case eStateSuspended:
+ case eStateStopped:
+ // Don't append anything for threads that should stay stopped.
+ break;
+
+ case eStateRunning:
+ if (m_process.GetUnixSignals().SignalIsValid (signo))
+ GetGDBProcess().m_continue_packet.Printf(";C%2.2x:%4.4x", signo, GetID());
+ else
+ GetGDBProcess().m_continue_packet.Printf(";c:%4.4x", GetID());
+ break;
+
+ case eStateStepping:
+ if (m_process.GetUnixSignals().SignalIsValid (signo))
+ GetGDBProcess().m_continue_packet.Printf(";S%2.2x:%4.4x", signo, GetID());
+ else
+ GetGDBProcess().m_continue_packet.Printf(";s:%4.4x", GetID());
+ break;
+ }
+ Thread::WillResume(resume_state);
+ return true;
+}
+
+void
+ThreadGDBRemote::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context
+ GetRegisterContext()->Invalidate();
+}
+
+Unwind *
+ThreadGDBRemote::GetUnwinder ()
+{
+ if (m_unwinder_ap.get() == NULL)
+ {
+ const ArchSpec target_arch (GetProcess().GetTarget().GetArchitecture ());
+ if (target_arch == ArchSpec("x86_64") || target_arch == ArchSpec("i386"))
+ {
+ m_unwinder_ap.reset (new UnwindLibUnwind (*this, GetGDBProcess().GetLibUnwindAddressSpace()));
+ }
+ else
+ {
+ m_unwinder_ap.reset (new UnwindMacOSXFrameBackchain (*this));
+ }
+ }
+ return m_unwinder_ap.get();
+}
+
+uint32_t
+ThreadGDBRemote::GetStackFrameCount()
+{
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ return unwinder->GetFrameCount();
+ return 0;
+}
+
+// Make sure that GetStackFrameAtIndex() does NOT call GetStackFrameCount() when
+// getting the stack frame at index zero! This way GetStackFrameCount() (via
+// GetStackFRameData()) can call this function to get the first frame in order
+// to provide the first frame to a lower call for efficiency sake (avoid
+// redundant lookups in the frame symbol context).
+lldb::StackFrameSP
+ThreadGDBRemote::GetStackFrameAtIndex (uint32_t idx)
+{
+
+ StackFrameSP frame_sp (m_frames.GetFrameAtIndex(idx));
+
+ if (frame_sp.get())
+ return frame_sp;
+
+ // Don't try and fetch a frame while process is running
+// 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 (m_process.IsRunning())
+// return frame_sp;
+
+ // Special case the first frame (idx == 0) so that we don't need to
+ // know how many stack frames there are to get it. If we need any other
+ // frames, then we do need to know if "idx" is a valid index.
+ if (idx == 0)
+ {
+ // If this is the first frame, we want to share the thread register
+ // context with the stack frame at index zero.
+ GetRegisterContext();
+ assert (m_reg_context_sp.get());
+ frame_sp.reset (new StackFrame (idx, *this, m_reg_context_sp, m_reg_context_sp->GetSP(), m_reg_context_sp->GetPC()));
+ }
+ else if (idx < GetStackFrameCount())
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ {
+ addr_t pc, cfa;
+ if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc))
+ frame_sp.reset (new StackFrame (idx, *this, cfa, pc));
+ }
+ }
+ m_frames.SetFrameAtIndex(idx, frame_sp);
+ return frame_sp;
+}
+
+void
+ThreadGDBRemote::ClearStackFrames ()
+{
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ unwinder->Clear();
+ Thread::ClearStackFrames();
+}
+
+
+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;
+}
+RegisterContext *
+ThreadGDBRemote::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL)
+ m_reg_context_sp.reset (CreateRegisterContextForFrame (NULL));
+ return m_reg_context_sp.get();
+}
+
+RegisterContext *
+ThreadGDBRemote::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ const bool read_all_registers_at_once = false;
+ uint32_t frame_idx = 0;
+
+ if (frame)
+ frame_idx = frame->GetID();
+
+ if (frame_idx == 0)
+ return new GDBRemoteRegisterContext (*this, frame, GetGDBProcess().m_register_info, read_all_registers_at_once);
+ else if (m_unwinder_ap.get() && frame_idx < m_unwinder_ap->GetFrameCount())
+ return m_unwinder_ap->CreateRegisterContextForFrame (frame);
+ return NULL;
+}
+
+bool
+ThreadGDBRemote::SaveFrameZeroState (RegisterCheckpoint &checkpoint)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ checkpoint.SetStackID(frame_sp->GetStackID());
+ return frame_sp->GetRegisterContext()->ReadAllRegisterValues (checkpoint.GetData());
+ }
+ return false;
+}
+
+bool
+ThreadGDBRemote::RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ bool ret = frame_sp->GetRegisterContext()->WriteAllRegisterValues (checkpoint.GetData());
+ frame_sp->GetRegisterContext()->Invalidate();
+ ClearStackFrames();
+ return ret;
+ }
+ return false;
+}
+
+bool
+ThreadGDBRemote::GetRawStopReason (StopInfo *stop_info)
+{
+ if (m_stop_info_stop_id != m_process.GetStopID())
+ {
+ char packet[256];
+ const int packet_len = snprintf(packet, sizeof(packet), "qThreadStopInfo%x", GetID());
+ assert (packet_len < (sizeof(packet) - 1));
+ StringExtractorGDBRemote stop_packet;
+ if (GetGDBProcess().GetGDBRemote().SendPacketAndWaitForResponse(packet, stop_packet, 1, false))
+ {
+ std::string copy(stop_packet.GetStringRef());
+ GetGDBProcess().SetThreadStopInfo (stop_packet);
+ // The process should have set the stop info stop ID and also
+ // filled this thread in with valid stop info
+ if (m_stop_info_stop_id != m_process.GetStopID())
+ {
+ //ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "warning: qThreadStopInfo problem: '%s' => '%s'", packet, stop_packet.GetStringRef().c_str());
+ printf("warning: qThreadStopInfo problem: '%s' => '%s'\n\torig '%s'\n", packet, stop_packet.GetStringRef().c_str(), copy.c_str()); /// REMOVE THIS
+ return false;
+ }
+ }
+ }
+ *stop_info = m_stop_info;
+ return true;
+}
+
+
diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
new file mode 100644
index 00000000000..3fa4ae09a2a
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
@@ -0,0 +1,156 @@
+//===-- 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"
+#include "MachException.h"
+#include "libunwind.h"
+
+class StringExtractor;
+class ProcessGDBRemote;
+
+class ThreadGDBRemote : public lldb_private::Thread
+{
+public:
+ ThreadGDBRemote (ProcessGDBRemote &process, lldb::tid_t tid);
+
+ virtual
+ ~ThreadGDBRemote ();
+
+ virtual bool
+ WillResume (lldb::StateType resume_state);
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual const char *
+ GetInfo ();
+
+ virtual const char *
+ GetName ();
+
+ virtual const char *
+ GetQueueName ();
+
+ virtual lldb_private::RegisterContext *
+ GetRegisterContext ();
+
+ virtual lldb_private::RegisterContext *
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ virtual bool
+ SaveFrameZeroState (RegisterCheckpoint &checkpoint);
+
+ virtual bool
+ RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint);
+
+ virtual uint32_t
+ GetStackFrameCount();
+
+ virtual lldb::StackFrameSP
+ GetStackFrameAtIndex (uint32_t idx);
+
+ virtual void
+ ClearStackFrames ();
+
+ ProcessGDBRemote &
+ GetGDBProcess ()
+ {
+ return (ProcessGDBRemote &)m_process;
+ }
+
+ const ProcessGDBRemote &
+ GetGDBProcess () const
+ {
+ return (ProcessGDBRemote &)m_process;
+ }
+
+ void
+ Dump (lldb_private::Log *log, uint32_t index);
+
+ static bool
+ ThreadIDIsValid (lldb::tid_t thread);
+
+ bool
+ ShouldStop (bool &step_more);
+
+ const char *
+ GetBasicInfoAsString ();
+
+ lldb_private::Thread::StopInfo &
+ GetStopInfoRef ()
+ {
+ return m_stop_info;
+ }
+
+ uint32_t
+ GetStopInfoStopID()
+ {
+ return m_stop_info_stop_id;
+ }
+
+ void
+ SetStopInfoStopID (uint32_t stop_id)
+ {
+ m_stop_info_stop_id = stop_id;
+ }
+
+ 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:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ uint32_t m_stop_info_stop_id;
+ lldb_private::Thread::StopInfo m_stop_info;
+ std::string m_thread_name;
+ std::string m_dispatch_queue_name;
+ lldb::addr_t m_thread_dispatch_qaddr;
+ std::auto_ptr<lldb_private::Unwind> m_unwinder_ap;
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+
+ lldb_private::Unwind *
+ GetUnwinder ();
+
+ void
+ SetStopInfoFromPacket (StringExtractor &stop_packet, uint32_t stop_id);
+
+ virtual bool
+ GetRawStopReason (StopInfo *stop_info);
+
+
+};
+
+#endif // liblldb_ThreadGDBRemote_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
new file mode 100644
index 00000000000..989e49452fb
--- /dev/null
+++ b/lldb/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, uint32_t* offset_ptr)
+{
+ return Extract(data, offset_ptr, data.GetULEB128(offset_ptr));
+}
+
+bool
+DWARFAbbreviationDeclaration::Extract(const DataExtractor& data, uint32_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;
+ dw_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/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h
new file mode 100644
index 00000000000..7959f264dfe
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h
@@ -0,0 +1,77 @@
+//===-- 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; }
+ uint32_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);
+ }
+ 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, uint32_t* offset_ptr);
+ bool Extract(const lldb_private::DataExtractor& data, uint32_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/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h
new file mode 100644
index 00000000000..0b44926cba0
--- /dev/null
+++ b/lldb/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 liblldb_DWARFAttribute_h_
+#define liblldb_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 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 = 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 // liblldb_DWARFAttribute_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
new file mode 100644
index 00000000000..e7f92c6eff2
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
@@ -0,0 +1,770 @@
+//===-- 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/Stream.h"
+#include "lldb/Core/Timer.h"
+
+#include "DWARFDebugAbbrev.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARF.h"
+
+using namespace lldb_private;
+using namespace std;
+
+extern int g_verbose;
+
+DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF* m_dwarf2Data) :
+ m_dwarf2Data ( m_dwarf2Data ),
+ 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 (),
+ m_aranges_ap (),
+ m_user_data ( NULL )
+{
+}
+
+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_aranges_ap.reset();
+ m_user_data = NULL;
+}
+
+bool
+DWARFCompileUnit::Extract(const DataExtractor &debug_info, uint32_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(dw_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 already hasn't 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
+ uint32_t offset = GetFirstDIEOffset();
+ const dw_offset_t next_cu_offset = GetNextCompileUnitOffset();
+ DWARFDebugInfoEntry die;
+ // Keep a flat array of the DIE for binary lookup by DIE offset
+ Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO);
+// if (log)
+// log->Printf("0x%8.8x: Compile Unit: length = 0x%8.8x, version = 0x%4.4x, abbr_offset = 0x%8.8x, addr_size = 0x%2.2x",
+// cu->GetOffset(),
+// cu->GetLength(),
+// cu->GetVersion(),
+// cu->GetAbbrevOffset(),
+// cu->GetAddressByteSize());
+
+ uint32_t depth = 0;
+ // We are in our compile unit, parse starting at the offset
+ // we were told to parse
+ while (die.Extract(m_dwarf2Data, this, &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() ? " *" : "");
+ if (cu_die_only)
+ {
+ AddDIE(die);
+ return 1;
+ }
+ else if (depth == 0 && initial_die_array_size == 1)
+ {
+ // Don't append the CU die as we already did that
+ }
+ else
+ {
+ AddDIE(die);
+ }
+
+ const DWARFAbbreviationDeclaration* abbrDecl = die.GetAbbreviationDeclarationPtr();
+ if (abbrDecl)
+ {
+ // Normal DIE
+ if (abbrDecl->HasChildren())
+ ++depth;
+ }
+ else
+ {
+ // NULL DIE.
+ if (depth > 0)
+ --depth;
+ else
+ break; // We are done with this compile unit!
+ }
+
+ assert(offset <= next_cu_offset);
+ }
+ SetDIERelations();
+ 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;
+}
+
+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())
+ {
+ if (m_aranges_ap.get() == NULL)
+ {
+ m_aranges_ap.reset(new DWARFDebugAranges());
+ m_die_array.front().BuildFunctionAddressRangeTable(m_dwarf2Data, this, m_aranges_ap.get());
+ }
+
+ // Re-check the aranges auto pointer contents in case it was created above
+ if (m_aranges_ap.get() != NULL)
+ {
+ *function_die_handle = GetDIEPtr(m_aranges_ap->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;
+}
+
+//----------------------------------------------------------------------
+// SetDIERelations()
+//
+// We read in all of the DIE entries into our flat list of DIE entries
+// and now we need to go back through all of them and set the parent,
+// sibling and child pointers for quick DIE navigation.
+//----------------------------------------------------------------------
+void
+DWARFCompileUnit::SetDIERelations()
+{
+#if 0
+ // Compute average bytes per DIE
+ //
+ // We can figure out what the average number of bytes per DIE is
+ // to help us pre-allocate the correct number of m_die_array
+ // entries so we don't end up doing a lot of memory copies as we
+ // are creating our DIE array when parsing
+ //
+ // Enable this code by changing "#if 0" above to "#if 1" and running
+ // the dsymutil or dwarfdump with a bunch of dwarf files and see what
+ // the running average ends up being in the stdout log.
+ static size_t g_total_cu_debug_info_size = 0;
+ static size_t g_total_num_dies = 0;
+ static size_t g_min_bytes_per_die = UINT_MAX;
+ static size_t g_max_bytes_per_die = 0;
+ const size_t num_dies = m_die_array.size();
+ const size_t cu_debug_info_size = GetDebugInfoSize();
+ const size_t bytes_per_die = cu_debug_info_size / num_dies;
+ if (g_min_bytes_per_die > bytes_per_die)
+ g_min_bytes_per_die = bytes_per_die;
+ if (g_max_bytes_per_die < bytes_per_die)
+ g_max_bytes_per_die = bytes_per_die;
+ if (g_total_cu_debug_info_size == 0)
+ {
+ cout << " min max avg" << endl
+ << "n dies cu size bpd bpd bpd bpd" << endl
+ << "------ -------- --- === === ===" << endl;
+ }
+ g_total_cu_debug_info_size += cu_debug_info_size;
+ g_total_num_dies += num_dies;
+ const size_t avg_bytes_per_die = g_total_cu_debug_info_size / g_total_num_dies;
+ cout
+ << DECIMAL_WIDTH(6) << num_dies << ' '
+ << DECIMAL_WIDTH(8) << cu_debug_info_size << ' '
+ << DECIMAL_WIDTH(3) << bytes_per_die << ' '
+ << DECIMAL_WIDTH(3) << g_min_bytes_per_die << ' '
+ << DECIMAL_WIDTH(3) << g_max_bytes_per_die << ' '
+ << DECIMAL_WIDTH(3) << avg_bytes_per_die
+ << endl;
+#endif
+ if (m_die_array.empty())
+ return;
+ DWARFDebugInfoEntry* die_array_begin = &m_die_array.front();
+ DWARFDebugInfoEntry* die_array_end = &m_die_array.back();
+ DWARFDebugInfoEntry* curr_die;
+ // We purposely are skipping the last element in the array in the loop below
+ // so that we can always have a valid next item
+ for (curr_die = die_array_begin; curr_die < die_array_end; ++curr_die)
+ {
+ // Since our loop doesn't include the last element, we can always
+ // safely access the next die in the array.
+ DWARFDebugInfoEntry* next_die = curr_die + 1;
+
+ const DWARFAbbreviationDeclaration* curr_die_abbrev = curr_die->GetAbbreviationDeclarationPtr();
+
+ if (curr_die_abbrev)
+ {
+ // Normal DIE
+ if (curr_die_abbrev->HasChildren())
+ next_die->SetParent(curr_die);
+ else
+ curr_die->SetSibling(next_die);
+ }
+ else
+ {
+ // NULL DIE that terminates a sibling chain
+ DWARFDebugInfoEntry* parent = curr_die->GetParent();
+ if (parent)
+ parent->SetSibling(next_die);
+ }
+ }
+
+ // Since we skipped the last element, we need to fix it up!
+ if (die_array_begin < die_array_end)
+ curr_die->SetParent(die_array_begin);
+
+#if 0
+ // The code below will dump the DIE relations in case any modification
+ // is done to the above code. This dump can be used in a diff to make
+ // sure that no functionality is lost.
+ {
+ DWARFDebugInfoEntry::const_iterator pos;
+ DWARFDebugInfoEntry::const_iterator end = m_die_array.end();
+ puts("offset parent sibling child");
+ puts("-------- -------- -------- --------");
+ for (pos = m_die_array.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();
+ printf("%.8x: %.8x %.8x %.8x\n", die_ref.GetOffset(),
+ p ? p->GetOffset() : 0,
+ s ? s->GetOffset() : 0,
+ c ? c->GetOffset() : 0);
+ }
+ }
+#endif
+
+}
+//----------------------------------------------------------------------
+// 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.Insert(&(*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
+(
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_function_die,
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_inlined_die,
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_global_die,
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_type_die
+)
+{
+
+ const DataExtractor* debug_str = &m_dwarf2Data->get_debug_str_data();
+
+ 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:
+ break;
+
+ default:
+ continue;
+ }
+
+ DWARFDebugInfoEntry::Attributes attributes;
+ const char *name = NULL;
+ const char *mangled = NULL;
+ bool is_variable = false;
+ bool is_declaration = false;
+ bool is_artificial = false;
+ bool has_address = false;
+ bool has_location = false;
+ bool is_global_or_static_variable = false;
+ const size_t num_attributes = die.GetAttributes(m_dwarf2Data, this, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+
+ dw_tag_t tag = die.Tag();
+
+ is_variable = tag == DW_TAG_variable;
+
+ 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(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:
+ if (attributes.ExtractFormValueAtIndex(m_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:
+ 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;
+ }
+ }
+ }
+
+ switch (tag)
+ {
+ case DW_TAG_subprogram:
+ if (has_address)
+ {
+ if (name && name[0])
+ {
+ if ((name[0] == '-' || name[0] == '+') && name[1] == '[')
+ {
+ 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 >= 6 && name[name_len - 1] == ']')
+ {
+ const char *method_name = strchr (name, ' ');
+ if (method_name)
+ {
+ // Skip the space
+ ++method_name;
+ // Extract the objective C basename and add it to the
+ // accelerator tables
+ size_t method_name_len = name_len - (method_name - name) - 1;
+ ConstString method_const_str (method_name, method_name_len);
+ name_to_function_die.Append(method_const_str.AsCString(), die.GetOffset());
+ }
+ }
+ }
+ name_to_function_die.Append(ConstString(name).AsCString(), die.GetOffset());
+ }
+ if (mangled && mangled[0])
+ name_to_function_die.Append(ConstString(mangled).AsCString(), die.GetOffset());
+ }
+ break;
+
+ case DW_TAG_inlined_subroutine:
+ if (has_address)
+ {
+ if (name && name[0])
+ name_to_inlined_die.Append(ConstString(name).AsCString(), die.GetOffset());
+ if (mangled && mangled[0])
+ name_to_inlined_die.Append(ConstString(mangled).AsCString(), 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_namespace:
+ if (name && is_declaration == false)
+ {
+ name_to_type_die.Append(ConstString(name).AsCString(), die.GetOffset());
+ }
+ break;
+
+ case DW_TAG_variable:
+ if (name && has_location && is_global_or_static_variable)
+ {
+ AddGlobalDIEByIndex (std::distance (begin, pos));
+ name_to_global_die.Append(ConstString(name).AsCString(), die.GetOffset());
+ }
+ break;
+
+ default:
+ continue;
+ }
+ }
+}
+
+
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
new file mode 100644
index 00000000000..44bbbfe5ba4
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
@@ -0,0 +1,168 @@
+//===-- 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 liblldb_DWARFCompileUnit_h_
+#define SymbolFileDWARF_DWARFCompileUnit_h_
+
+#include "SymbolFileDWARF.h"
+#include "DWARFDebugInfoEntry.h"
+
+class DWARFCompileUnit
+{
+public:
+ DWARFCompileUnit(SymbolFileDWARF* dwarf2Data);
+
+ bool Extract(const lldb_private::DataExtractor &debug_info, uint32_t* offset_ptr);
+ dw_offset_t Extract(dw_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 = UINT_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
+ SetBaseAddress(dw_addr_t base_addr)
+ {
+ m_base_addr = base_addr;
+ }
+
+ void
+ SetDIERelations();
+
+ 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 the needed memory for
+ // our DIE entries accordingly. Search forward for "Compute
+ // average bytes per DIE" to see #if'ed out code that does
+ // that determination.
+
+ // 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() / 14);
+ m_die_array.push_back(die);
+ }
+
+ 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;
+ }
+
+
+ void
+ AddGlobalDIEByIndex (uint32_t die_idx);
+
+ void
+ AddGlobal (const DWARFDebugInfoEntry* die);
+
+ size_t
+ GetNumGlobals () const
+ {
+ return m_global_die_indexes.size();
+ }
+
+ const DWARFDebugInfoEntry *
+ GetGlobalDIEAtIndex (uint32_t idx)
+ {
+ if (idx < m_global_die_indexes.size())
+ {
+ uint32_t die_idx = m_global_die_indexes[idx];
+ if (die_idx < m_die_array.size())
+ return &m_die_array[die_idx];
+ }
+ return NULL;
+ }
+
+ void
+ Index (lldb_private::UniqueCStringMap<dw_offset_t>& name_to_function_die,
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_inlined_die,
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_global_die,
+ lldb_private::UniqueCStringMap<dw_offset_t>& name_to_type_die);
+
+protected:
+ SymbolFileDWARF* m_dwarf2Data;
+ dw_offset_t m_offset;
+ uint32_t m_length;
+ uint16_t m_version;
+ const DWARFAbbreviationDeclarationSet*
+ m_abbrevs;
+ uint8_t m_addr_size;
+ dw_addr_t m_base_addr;
+ DWARFDebugInfoEntry::collection
+ m_die_array; // The compile unit debug information entry item
+ std::auto_ptr<DWARFDebugAranges> m_aranges_ap; // A table similar to the .debug_aranges table, but this one points to the exact DW_TAG_subprogram DIEs
+ std::vector<uint32_t> m_global_die_indexes; // Indexes to all file level global and static variables
+ void * m_user_data;
+private:
+ DISALLOW_COPY_AND_ASSIGN (DWARFCompileUnit);
+};
+
+#endif // SymbolFileDWARF_DWARFCompileUnit_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp
new file mode 100644
index 00000000000..60aac74ad86
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp
@@ -0,0 +1,56 @@
+//===-- 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;
+}
+
+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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h
new file mode 100644
index 00000000000..c374a148c6c
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h
@@ -0,0 +1,48 @@
+//===-- 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 liblldb_DWARFDIECollection_h_
+#define SymbolFileDWARF_DWARFDIECollection_h_
+
+#include "SymbolFileDWARF.h"
+#include <vector>
+
+class DWARFDIECollection
+{
+public:
+ DWARFDIECollection() :
+ m_dies()
+ {
+ }
+ ~DWARFDIECollection()
+ {
+ }
+
+ 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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
new file mode 100644
index 00000000000..af6fc8e93e7
--- /dev/null
+++ b/lldb/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, uint32_t* offset_ptr)
+{
+ const uint32_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 = UINT_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 == UINT_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 represenation 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)
+{
+ uint32_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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
new file mode 100644
index 00000000000..3185d9895a3
--- /dev/null
+++ b/lldb/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 liblldb_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, uint32_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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
new file mode 100644
index 00000000000..57ef6ba4eb4
--- /dev/null
+++ b/lldb/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, uint32_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%*.*llx - 0x%*.*llx)\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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h
new file mode 100644
index 00000000000..fc1e391aeb4
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h
@@ -0,0 +1,70 @@
+//===-- 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 liblldb_DWARFDebugArangeSet_h_
+#define SymbolFileDWARF_DWARFDebugArangeSet_h_
+
+#include "SymbolFileDWARF.h"
+#include <vector>
+
+class SymbolFileDWARF;
+
+class DWARFDebugArangeSet
+{
+public:
+ typedef struct HeaderTag
+ {
+ 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.
+ } Header;
+
+ typedef struct DescriptorTag
+ {
+ dw_addr_t address;
+ dw_addr_t length;
+ dw_addr_t end_address() const { return address + length; }
+ } Descriptor;
+
+
+ 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, uint32_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;
+ uint32_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;
+ }
+
+
+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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
new file mode 100644
index 00000000000..a3213e080c3
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
@@ -0,0 +1,343 @@
+//===-- 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 <algorithm>
+
+#include "lldb/Core/Stream.h"
+
+#include "SymbolFileDWARF.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFCompileUnit.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DWARFDebugAranges::DWARFDebugAranges() :
+ m_aranges()
+{
+}
+
+
+//----------------------------------------------------------------------
+// Compare function DWARFDebugAranges::Range structures
+//----------------------------------------------------------------------
+static bool RangeLessThan (const DWARFDebugAranges::Range& range1, const DWARFDebugAranges::Range& range2)
+{
+// printf("RangeLessThan -- 0x%8.8x < 0x%8.8x ? %d\n", range1.lo_pc, range1.lo_pc, range1.lo_pc < range2.lo_pc);
+ return range1.lo_pc < range2.lo_pc;
+}
+
+//----------------------------------------------------------------------
+// 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;
+};
+
+//----------------------------------------------------------------------
+// AddArangeDescriptors
+//----------------------------------------------------------------------
+class AddArangeDescriptors
+{
+public:
+ AddArangeDescriptors (DWARFDebugAranges::RangeColl& ranges) : range_collection(ranges) {}
+ void operator() (const DWARFDebugArangeSet& set)
+ {
+ const DWARFDebugArangeSet::Descriptor* arange_desc_ptr;
+ DWARFDebugAranges::Range range;
+ range.offset = set.GetCompileUnitDIEOffset();
+
+ for (uint32_t i=0; arange_desc_ptr = set.GetDescriptor(i); ++i)
+ {
+ range.lo_pc = arange_desc_ptr->address;
+ range.hi_pc = arange_desc_ptr->address + arange_desc_ptr->length;
+
+ // Insert each item in increasing address order so binary searching
+ // can later be done!
+ DWARFDebugAranges::RangeColl::iterator insert_pos = lower_bound(range_collection.begin(), range_collection.end(), range, RangeLessThan);
+ range_collection.insert(insert_pos, range);
+ }
+ }
+ DWARFDebugAranges::RangeColl& range_collection;
+};
+
+//----------------------------------------------------------------------
+// PrintRange
+//----------------------------------------------------------------------
+static void PrintRange(const DWARFDebugAranges::Range& range)
+{
+ // Cast the address values in case the address type is compiled as 32 bit
+ printf("0x%8.8x: [0x%8.8llx - 0x%8.8llx)\n", range.offset, (uint64_t)range.lo_pc, (uint64_t)range.hi_pc);
+}
+
+//----------------------------------------------------------------------
+// Extract
+//----------------------------------------------------------------------
+bool
+DWARFDebugAranges::Extract(const DataExtractor &debug_aranges_data)
+{
+ if (debug_aranges_data.ValidOffset(0))
+ {
+ uint32_t offset = 0;
+
+ typedef std::vector<DWARFDebugArangeSet> SetCollection;
+ typedef SetCollection::const_iterator SetCollectionIter;
+ SetCollection sets;
+
+ DWARFDebugArangeSet set;
+ Range range;
+ while (set.Extract(debug_aranges_data, &offset))
+ sets.push_back(set);
+
+ uint32_t count = 0;
+
+ for_each(sets.begin(), sets.end(), CountArangeDescriptors(count));
+
+ if (count > 0)
+ {
+ m_aranges.reserve(count);
+ AddArangeDescriptors range_adder(m_aranges);
+ for_each(sets.begin(), sets.end(), range_adder);
+ }
+
+ // puts("\n\nDWARFDebugAranges list is:\n");
+ // for_each(m_aranges.begin(), m_aranges.end(), PrintRange);
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Generate
+//----------------------------------------------------------------------
+bool
+DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data)
+{
+ 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);
+ if (cu)
+ cu->DIE()->BuildAddressRangeTable(dwarf2Data, cu, this);
+ }
+ }
+ return !IsEmpty();
+}
+
+
+void
+DWARFDebugAranges::Print() const
+{
+ puts("\n\nDWARFDebugAranges address range list is:\n");
+ for_each(m_aranges.begin(), m_aranges.end(), PrintRange);
+}
+
+
+void
+DWARFDebugAranges::Range::Dump(Stream *s) const
+{
+ s->Printf("{0x%8.8x}: [0x%8.8llx - 0x%8.8llx)\n", offset, lo_pc, hi_pc);
+}
+
+//----------------------------------------------------------------------
+// Dump
+//----------------------------------------------------------------------
+void
+DWARFDebugAranges::Dump(SymbolFileDWARF* dwarf2Data, Stream *s)
+{
+ const DataExtractor &debug_aranges_data = dwarf2Data->get_debug_aranges_data();
+ if (debug_aranges_data.ValidOffset(0))
+ {
+ uint32_t offset = 0;
+
+ DWARFDebugArangeSet set;
+ while (set.Extract(debug_aranges_data, &offset))
+ set.Dump(s);
+ }
+ else
+ s->PutCString("< EMPTY >\n");
+}
+
+
+//----------------------------------------------------------------------
+// AppendDebugRanges
+//----------------------------------------------------------------------
+//void
+//DWARFDebugAranges::AppendDebugRanges(BinaryStreamBuf& debug_ranges, dw_addr_t cu_base_addr, uint32_t addr_size) const
+//{
+// if (!m_aranges.empty())
+// {
+// RangeCollIterator end = m_aranges.end();
+// RangeCollIterator pos;
+// RangeCollIterator lo_pos = end;
+// for (pos = m_aranges.begin(); pos != end; ++pos)
+// {
+// if (lo_pos == end)
+// lo_pos = pos;
+//
+// RangeCollIterator next = pos + 1;
+// if (next != end)
+// {
+// // Check to see if we can combine two consecutive ranges?
+// if (pos->hi_pc == next->lo_pc)
+// continue; // We can combine them!
+// }
+//
+// if (cu_base_addr == 0 || cu_base_addr == DW_INVALID_ADDRESS)
+// {
+// debug_ranges.AppendMax64(lo_pos->lo_pc, addr_size);
+// debug_ranges.AppendMax64(pos->hi_pc, addr_size);
+// }
+// else
+// {
+// assert(lo_pos->lo_pc >= cu_base_addr);
+// assert(pos->hi_pc >= cu_base_addr);
+// debug_ranges.AppendMax64(lo_pos->lo_pc - cu_base_addr, addr_size);
+// debug_ranges.AppendMax64(pos->hi_pc - cu_base_addr, addr_size);
+// }
+//
+// // Reset the low part of the next address range
+// lo_pos = end;
+// }
+// }
+// // Terminate the .debug_ranges with two zero addresses
+// debug_ranges.AppendMax64(0, addr_size);
+// debug_ranges.AppendMax64(0, addr_size);
+//
+//}
+//
+//----------------------------------------------------------------------
+// ArangeSetContainsAddress
+//----------------------------------------------------------------------
+class ArangeSetContainsAddress
+{
+public:
+ ArangeSetContainsAddress (dw_addr_t the_address) : address(the_address), offset(DW_INVALID_OFFSET) {}
+ bool operator() (const DWARFDebugArangeSet& set)
+ {
+ offset = set.FindAddress(address);
+ return (offset != DW_INVALID_OFFSET);
+ }
+ const dw_addr_t address;
+ dw_offset_t offset;
+};
+
+
+//----------------------------------------------------------------------
+// InsertRange
+//----------------------------------------------------------------------
+void
+DWARFDebugAranges::InsertRange(dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc)
+{
+ // Insert each item in increasing address order so binary searching
+ // can later be done!
+ DWARFDebugAranges::Range range(low_pc, high_pc, offset);
+ InsertRange(range);
+}
+
+//----------------------------------------------------------------------
+// InsertRange
+//----------------------------------------------------------------------
+void
+DWARFDebugAranges::InsertRange(const DWARFDebugAranges::Range& range)
+{
+ // Insert each item in increasing address order so binary searching
+ // can later be done!
+ RangeColl::iterator insert_pos = lower_bound(m_aranges.begin(), m_aranges.end(), range, RangeLessThan);
+ m_aranges.insert(insert_pos, range);
+}
+
+
+//----------------------------------------------------------------------
+// FindAddress
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugAranges::FindAddress(dw_addr_t address) const
+{
+ if ( !m_aranges.empty() )
+ {
+ DWARFDebugAranges::Range range(address);
+ DWARFDebugAranges::RangeCollIterator begin = m_aranges.begin();
+ DWARFDebugAranges::RangeCollIterator end = m_aranges.end();
+ DWARFDebugAranges::RangeCollIterator pos = lower_bound(begin, end, range, RangeLessThan);
+
+ if ((pos != end) && (pos->lo_pc <= address && address < pos->hi_pc))
+ {
+ // printf("FindAddress(1) found 0x%8.8x in compile unit: 0x%8.8x\n", address, pos->offset);
+ return pos->offset;
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if ((pos->lo_pc <= address) && (address < pos->hi_pc))
+ {
+ // printf("FindAddress(2) found 0x%8.8x in compile unit: 0x%8.8x\n", address, pos->offset);
+ return (*pos).offset;
+ }
+ }
+ }
+ return DW_INVALID_OFFSET;
+}
+
+//----------------------------------------------------------------------
+// AllRangesAreContiguous
+//----------------------------------------------------------------------
+bool
+DWARFDebugAranges::AllRangesAreContiguous(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const
+{
+ if (m_aranges.empty())
+ return false;
+
+ DWARFDebugAranges::RangeCollIterator begin = m_aranges.begin();
+ DWARFDebugAranges::RangeCollIterator end = m_aranges.end();
+ DWARFDebugAranges::RangeCollIterator pos;
+ dw_addr_t next_addr = 0;
+
+ for (pos = begin; pos != end; ++pos)
+ {
+ if ((pos != begin) && (pos->lo_pc != next_addr))
+ return false;
+ next_addr = pos->hi_pc;
+ }
+ lo_pc = m_aranges.front().lo_pc; // We checked for empty at the start of function so front() will be valid
+ hi_pc = m_aranges.back().hi_pc; // We checked for empty at the start of function so back() will be valid
+ return true;
+}
+
+bool
+DWARFDebugAranges::GetMaxRange(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const
+{
+ if (m_aranges.empty())
+ return false;
+
+ lo_pc = m_aranges.front().lo_pc; // We checked for empty at the start of function so front() will be valid
+ hi_pc = m_aranges.back().hi_pc; // We checked for empty at the start of function so back() will be valid
+ return true;
+}
+
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
new file mode 100644
index 00000000000..f3db949bf26
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
@@ -0,0 +1,98 @@
+//===-- 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 liblldb_DWARFDebugAranges_h_
+#define SymbolFileDWARF_DWARFDebugAranges_h_
+
+#include "DWARFDebugArangeSet.h"
+#include <list>
+
+class SymbolFileDWARF;
+
+class DWARFDebugAranges
+{
+public:
+ struct Range
+ {
+ Range(
+ dw_addr_t _lo_pc = DW_INVALID_ADDRESS,
+ dw_addr_t _hi_pc = DW_INVALID_ADDRESS,
+ dw_offset_t _offset = DW_INVALID_OFFSET) :
+ lo_pc(_lo_pc),
+ hi_pc(_hi_pc),
+ offset(_offset)
+ {
+ }
+
+ void Clear()
+ {
+ lo_pc = hi_pc = DW_INVALID_ADDRESS;
+ offset = DW_INVALID_OFFSET;
+ }
+
+ bool ValidRange() const
+ {
+ return hi_pc > lo_pc;
+ }
+
+ bool Contains(const Range& range) const
+ {
+ return lo_pc <= range.lo_pc && range.hi_pc <= hi_pc;
+ }
+
+ void Dump(lldb_private::Stream *s) const;
+ dw_addr_t lo_pc; // Start of address range
+ dw_addr_t hi_pc; // End of address range (not including this address)
+ dw_offset_t offset; // Offset of the compile unit or die
+ };
+
+ DWARFDebugAranges();
+
+ void Clear() { m_aranges.clear(); }
+ bool AllRangesAreContiguous(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const;
+ bool GetMaxRange(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const;
+ bool Extract(const lldb_private::DataExtractor &debug_aranges_data);
+ bool Generate(SymbolFileDWARF* dwarf2Data);
+ void InsertRange(dw_offset_t cu_offset, dw_addr_t low_pc, dw_addr_t high_pc);
+ void InsertRange(const DWARFDebugAranges::Range& range);
+ const Range* RangeAtIndex(uint32_t idx) const
+ {
+ if (idx < m_aranges.size())
+ return &m_aranges[idx];
+ return NULL;
+ }
+ void Print() const;
+ dw_offset_t FindAddress(dw_addr_t address) const;
+ bool IsEmpty() const { return m_aranges.empty(); }
+ void Dump(lldb_private::Stream *s);
+ uint32_t NumRanges() const
+ {
+ return m_aranges.size();
+ }
+
+ dw_offset_t OffsetAtIndex(uint32_t idx) const
+ {
+ if (idx < m_aranges.size())
+ return m_aranges[idx].offset;
+ return DW_INVALID_OFFSET;
+ }
+// void AppendDebugRanges(BinaryStreamBuf& debug_ranges, dw_addr_t cu_base_addr, uint32_t addr_size) const;
+
+ static void Dump(SymbolFileDWARF* dwarf2Data, lldb_private::Stream *s);
+
+ typedef std::vector<Range> RangeColl;
+ typedef RangeColl::const_iterator RangeCollIterator;
+
+protected:
+
+ RangeColl m_aranges;
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugAranges_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
new file mode 100644
index 00000000000..fcb0ccf1189
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -0,0 +1,1206 @@
+//===-- 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 "DWARFDebugInfo.h"
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfoEntry.h"
+#include "DWARFFormValue.h"
+
+using namespace lldb_private;
+using namespace std;
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DWARFDebugInfo::DWARFDebugInfo() :
+ m_dwarf2Data(NULL),
+ m_compile_units()
+{
+}
+
+//----------------------------------------------------------------------
+// SetDwarfData
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::SetDwarfData(SymbolFileDWARF* dwarf2Data)
+{
+ m_dwarf2Data = dwarf2Data;
+ m_compile_units.clear();
+}
+
+//----------------------------------------------------------------------
+// BuildDIEAddressRangeTable
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfo::BuildFunctionAddressRangeTable(DWARFDebugAranges* debug_aranges)
+{
+ const uint32_t num_compile_units = GetNumCompileUnits();
+ uint32_t idx;
+ for (idx = 0; idx < num_compile_units; ++idx)
+ {
+ DWARFCompileUnit* cu = GetCompileUnitAtIndex (idx);
+ if (cu)
+ {
+ cu->DIE()->BuildFunctionAddressRangeTable(m_dwarf2Data, cu, debug_aranges);
+ }
+ }
+ return !debug_aranges->IsEmpty();
+}
+
+//----------------------------------------------------------------------
+// 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
+ {
+ // Get a non const version of the address ranges
+ DWARFDebugAranges* debug_aranges = ((SymbolFileDWARF*)m_dwarf2Data)->DebugAranges();
+
+ if (debug_aranges != NULL)
+ {
+ // If we have an empty address ranges section, lets build a sorted
+ // table ourselves by going through all of the debug information so we
+ // can do quick subsequent searches.
+
+ if (debug_aranges->IsEmpty())
+ {
+ const uint32_t num_compile_units = GetNumCompileUnits();
+ uint32_t idx;
+ for (idx = 0; idx < num_compile_units; ++idx)
+ {
+ DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx);
+ if (cu)
+ cu->DIE()->BuildAddressRangeTable(m_dwarf2Data, cu, debug_aranges);
+ }
+ }
+ cu_sp = GetCompileUnit(debug_aranges->FindAddress(address));
+ }
+ }
+
+ 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)
+ {
+ uint32_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();
+ }
+ }
+ }
+}
+
+uint32_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;
+}
+
+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
+}
+
+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)
+ {
+ uint32_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 funtion 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 funtion 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 propper
+ offset = next_cu_offset;
+ }
+ }
+}
+
+/*
+typedef struct AddressRangeTag
+{
+ dw_addr_t lo_pc;
+ dw_addr_t hi_pc;
+ dw_offset_t die_offset;
+} AddressRange;
+*/
+struct DIERange
+{
+ DIERange() :
+ range(),
+ lo_die_offset(),
+ hi_die_offset()
+ {
+ }
+
+ DWARFDebugAranges::Range range;
+ dw_offset_t lo_die_offset;
+ dw_offset_t hi_die_offset;
+};
+
+typedef struct DwarfStat
+{
+ DwarfStat() : count(0), byte_size(0) {}
+ uint32_t count;
+ uint32_t byte_size;
+} DwarfStat;
+
+typedef map<dw_attr_t, DwarfStat> DwarfAttrStatMap;
+
+typedef struct DIEStat
+{
+ DIEStat() : count(0), byte_size(0), attr_stats() {}
+ uint32_t count;
+ uint32_t byte_size;
+ DwarfAttrStatMap attr_stats;
+} DIEStat;
+
+typedef map<dw_tag_t, DIEStat> DIEStatMap;
+struct VerifyInfo
+{
+ VerifyInfo(Stream* the_strm) :
+ strm(the_strm),
+ die_ranges(),
+ addr_range_errors(0),
+ sibling_errors(0),
+ die_stats()
+ {
+ }
+
+ Stream* strm;
+ vector<DIERange> die_ranges;
+ uint32_t addr_range_errors;
+ uint32_t sibling_errors;
+ DIEStatMap die_stats;
+
+ DISALLOW_COPY_AND_ASSIGN(VerifyInfo);
+
+};
+
+
+//----------------------------------------------------------------------
+// VerifyCallback
+//
+// 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 verify the DWARF information is well formed by
+// making sure that any DW_TAG_compile_unit tags that have valid address
+// ranges (DW_AT_low_pc and DW_AT_high_pc) have no gaps in the address
+// ranges of it contained DW_TAG_subprogram tags. Also the sibling chain
+// and relationships are verified to make sure nothing gets hosed up
+// when dead stripping occurs.
+//----------------------------------------------------------------------
+
+static dw_offset_t
+VerifyCallback
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t curr_depth,
+ void* userData
+)
+{
+ VerifyInfo* verifyInfo = (VerifyInfo*)userData;
+
+ const DWARFCompileUnit* cu = cu_sp.get();
+ Stream *s = verifyInfo->strm;
+ bool verbose = s->GetVerbose();
+ if (die)
+ {
+ // die->Dump(dwarf2Data, cu, f);
+ const DWARFAbbreviationDeclaration* abbrevDecl = die->GetAbbreviationDeclarationPtr();
+ // We have a DIE entry
+ if (abbrevDecl)
+ {
+ const dw_offset_t die_offset = die->GetOffset();
+ const dw_offset_t sibling = die->GetAttributeValueAsReference(dwarf2Data, cu, DW_AT_sibling, DW_INVALID_OFFSET);
+
+ if (sibling != DW_INVALID_OFFSET)
+ {
+ if (sibling <= next_offset)
+ {
+ if (verifyInfo->sibling_errors++ == 0)
+ s->Printf("ERROR\n");
+ s->Printf(" 0x%8.8x: sibling attribyte (0x%8.8x) in this die is not valid: it is less than this DIE or some of its contents.\n", die->GetOffset(), sibling);
+ }
+ else if (sibling > verifyInfo->die_ranges.back().hi_die_offset)
+ {
+ if (verifyInfo->sibling_errors++ == 0)
+ s->Printf("ERROR\n");
+ s->Printf(" 0x%8.8x: sibling attribute (0x%8.8x) in this DIE is not valid: it is greater than the end of the parent scope.\n", die->GetOffset(), sibling);
+ }
+ }
+
+ if ((die_offset < verifyInfo->die_ranges.back().lo_die_offset) || (die_offset >= verifyInfo->die_ranges.back().hi_die_offset))
+ {
+ if (verifyInfo->sibling_errors++ == 0)
+ s->Printf("ERROR\n");
+ s->Printf(" 0x%8.8x: DIE offset is not within the parent DIE range {0x%8.8x}: (0x%8.8x - 0x%8.8x)\n",
+ die->GetOffset(),
+ verifyInfo->die_ranges.back().range.offset,
+ verifyInfo->die_ranges.back().lo_die_offset,
+ verifyInfo->die_ranges.back().hi_die_offset);
+
+ }
+
+ dw_tag_t tag = abbrevDecl->Tag();
+
+ // Keep some stats on this DWARF file
+ verifyInfo->die_stats[tag].count++;
+ verifyInfo->die_stats[tag].byte_size += (next_offset - die->GetOffset());
+
+ if (verbose)
+ {
+ DIEStat& tag_stat = verifyInfo->die_stats[tag];
+
+ const DataExtractor& debug_info = dwarf2Data->get_debug_info_data();
+
+ dw_offset_t offset = die->GetOffset();
+ // Skip the abbreviation code so we are at the data for the attributes
+ debug_info.Skip_LEB128(&offset);
+
+ const uint32_t numAttributes = abbrevDecl->NumAttributes();
+ dw_attr_t attr;
+ dw_form_t form;
+ for (uint32_t idx = 0; idx < numAttributes; ++idx)
+ {
+ dw_offset_t start_offset = offset;
+ abbrevDecl->GetAttrAndFormByIndexUnchecked(idx, attr, form);
+ DWARFFormValue::SkipValue(form, debug_info, &offset, cu);
+
+ if (tag_stat.attr_stats.find(attr) == tag_stat.attr_stats.end())
+ {
+ tag_stat.attr_stats[attr].count = 0;
+ tag_stat.attr_stats[attr].byte_size = 0;
+ }
+
+ tag_stat.attr_stats[attr].count++;
+ tag_stat.attr_stats[attr].byte_size += offset - start_offset;
+ }
+ }
+
+ DWARFDebugAranges::Range range;
+ range.offset = die->GetOffset();
+
+ switch (tag)
+ {
+ case DW_TAG_compile_unit:
+ // Check for previous subroutines that were within a previous
+ //
+ // VerifyAddressRangesForCU(verifyInfo);
+ // Remember which compile unit we are dealing with so we can verify
+ // the address ranges within it (if any) are contiguous. The DWARF
+ // spec states that if a compile unit TAG has high and low PC
+ // attributes, there must be no gaps in the address ranges of it's
+ // contained subtroutines. If there are gaps, the high and low PC
+ // must not be in the DW_TAG_compile_unit's attributes. Errors like
+ // this can crop up when optimized code is dead stripped and the debug
+ // information isn't properly fixed up for output.
+ range.lo_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (range.lo_pc != DW_INVALID_ADDRESS)
+ {
+ range.hi_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (s->GetVerbose())
+ {
+ s->Printf("\n CU ");
+ range.Dump(s);
+ }
+ }
+ else
+ {
+ range.lo_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_entry_pc, DW_INVALID_ADDRESS);
+ }
+ break;
+
+ case DW_TAG_subprogram:
+ // If the DW_TAG_compile_unit that contained this function had a
+ // valid address range, add all of the valid subroutine address
+ // ranges to a collection of addresses which will be sorted
+ // and verified right before the next DW_TAG_compile_unit is
+ // processed to make sure that there are no gaps in the address
+ // range.
+ range.lo_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (range.lo_pc != DW_INVALID_ADDRESS)
+ {
+ range.hi_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (range.hi_pc != DW_INVALID_ADDRESS)
+ {
+ range.offset = die->GetOffset();
+ bool valid = range.ValidRange();
+ if (!valid || s->GetVerbose())
+ {
+ s->Printf("\n FUNC ");
+ range.Dump(s);
+ if (!valid)
+ {
+ ++verifyInfo->addr_range_errors;
+ s->Printf(" ERROR: Invalid address range for function.");
+ }
+ }
+
+ // Only add to our subroutine ranges if our compile unit has a valid address range
+ // if (valid && verifyInfo->die_ranges.size() >= 2 && verifyInfo->die_ranges[1].range.ValidRange())
+ // verifyInfo->subroutine_ranges.InsertRange(range);
+ }
+ }
+ break;
+
+ case DW_TAG_lexical_block:
+ case DW_TAG_inlined_subroutine:
+ {
+ range.lo_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (range.lo_pc != DW_INVALID_ADDRESS)
+ {
+ range.hi_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (range.hi_pc != DW_INVALID_ADDRESS)
+ {
+ range.offset = die->GetOffset();
+ bool valid = range.ValidRange();
+ if (!valid || s->GetVerbose())
+ {
+ s->Printf("\n BLCK ");
+ range.Dump(s);
+ if (!valid)
+ {
+ ++verifyInfo->addr_range_errors;
+ s->Printf(" ERROR: Invalid address range for block or inlined subroutine.");
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ if (range.ValidRange() && verifyInfo->die_ranges.back().range.ValidRange())
+ {
+ if (!verifyInfo->die_ranges.back().range.Contains(range))
+ {
+ ++verifyInfo->addr_range_errors;
+ s->Printf("\n ");
+ range.Dump(s);
+ s->Printf(" ERROR: Range is not in parent");
+ verifyInfo->die_ranges.back().range.Dump(s);
+ }
+ }
+
+ if (die->HasChildren())
+ {
+ // Keep tabs on the valid address ranges for the current item to make
+ // sure that it all fits (make sure the sibling offsets got fixed up
+ // correctly if any functions were dead stripped).
+ DIERange die_range;
+ die_range.range = range;
+ die_range.lo_die_offset = next_offset;
+ die_range.hi_die_offset = sibling;
+ if (die_range.hi_die_offset == DW_INVALID_OFFSET)
+ die_range.hi_die_offset = verifyInfo->die_ranges.back().hi_die_offset;
+ verifyInfo->die_ranges.push_back(die_range);
+ }
+ }
+ else
+ {
+ // NULL entry
+ verifyInfo->die_ranges.pop_back();
+ }
+ }
+ else
+ {
+ // cu->Dump(ostrm_ptr); // Dump the compile unit for the DIE
+ // We have a new comile unit header
+ verifyInfo->die_ranges.clear();
+ DIERange die_range;
+ die_range.range.offset = cu->GetOffset();
+ die_range.lo_die_offset = next_offset;
+ die_range.hi_die_offset = cu->GetNextCompileUnitOffset();
+ verifyInfo->die_ranges.push_back(die_range);
+ }
+
+ // Just return the current offset to parse the next CU or DIE entry
+ return next_offset;
+}
+
+
+class CompareDIEStatSizes
+{
+public:
+ bool operator() (const DIEStatMap::const_iterator& pos1, const DIEStatMap::const_iterator& pos2) const
+ {
+ return pos1->second.byte_size <= pos2->second.byte_size;
+ }
+};
+
+class CompareAttrDIEStatSizes
+{
+public:
+ bool operator() (const DwarfAttrStatMap::const_iterator& pos1, const DwarfAttrStatMap::const_iterator& pos2) const
+ {
+ return pos1->second.byte_size <= pos2->second.byte_size;
+ }
+};
+
+//----------------------------------------------------------------------
+// Verify
+//
+// Verifies the DWARF information is valid.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::Verify(Stream *s, SymbolFileDWARF* dwarf2Data)
+{
+ s->Printf("Verifying Compile Unit Header chain.....");
+ VerifyInfo verifyInfo(s);
+ verifyInfo.addr_range_errors = 0;
+ verifyInfo.sibling_errors = 0;
+
+ bool verbose = s->GetVerbose();
+
+ uint32_t offset = 0;
+ if (verbose)
+ s->EOL();
+// vector<dw_offset_t> valid_cu_offsets;
+ DWARFCompileUnit cu (dwarf2Data);
+ bool success = true;
+ while ( success && dwarf2Data->get_debug_info_data().ValidOffset(offset+cu.Size()) )
+ {
+ success = cu.Extract (dwarf2Data->get_debug_info_data(), &offset);
+ if (!success)
+ s->Printf("ERROR\n");
+ // else
+ // valid_cu_offsets.push_back(cu.GetOffset());
+
+ cu.Verify(verifyInfo.strm);
+ offset = cu.GetNextCompileUnitOffset();
+ }
+
+ if (success)
+ s->Printf("OK\n");
+
+ s->Printf("Verifying address ranges and siblings...");
+ if (verbose)
+ s->EOL();
+ DWARFDebugInfo::Parse(dwarf2Data, VerifyCallback, &verifyInfo);
+
+// VerifyAddressRangesForCU(&verifyInfo);
+
+ if (verifyInfo.addr_range_errors > 0)
+ s->Printf("\nERRORS - %u error(s) were found.\n", verifyInfo.addr_range_errors);
+ else
+ s->Printf("OK\n");
+
+ uint32_t total_category_sizes[kNumTagCategories] = {0};
+ uint32_t total_category_count[kNumTagCategories] = {0};
+ uint32_t total_die_count = 0;
+ uint32_t total_die_size = 0;
+
+ typedef set<DIEStatMap::const_iterator, CompareDIEStatSizes> DIEStatBySizeMap;
+
+ s->PutCString( "\n"
+ "DWARF Statistics\n"
+ "Count Size Size % Tag\n"
+ "-------- -------- -------- -------------------------------------------\n");
+ DIEStatBySizeMap statBySizeMap;
+ DIEStatMap::const_iterator pos;
+ DIEStatMap::const_iterator end_pos = verifyInfo.die_stats.end();
+ for (pos = verifyInfo.die_stats.begin(); pos != end_pos; ++pos)
+ {
+ const uint32_t die_count = pos->second.count;
+ const uint32_t die_size = pos->second.byte_size;
+
+ statBySizeMap.insert(pos);
+ total_die_count += die_count;
+ total_die_size += die_size;
+ DW_TAG_CategoryEnum category = get_tag_category(pos->first);
+ total_category_sizes[category] += die_size;
+ total_category_count[category] += die_count;
+ }
+
+ float total_die_size_float = total_die_size;
+
+ DIEStatBySizeMap::const_reverse_iterator size_pos;
+ DIEStatBySizeMap::const_reverse_iterator size_pos_end = statBySizeMap.rend();
+ float percentage;
+ for (size_pos = statBySizeMap.rbegin(); size_pos != size_pos_end; ++size_pos)
+ {
+ pos = *size_pos;
+
+ const DIEStat& tag_stat = pos->second;
+
+ const uint32_t die_count = tag_stat.count;
+ const uint32_t die_size = tag_stat.byte_size;
+ percentage = ((float)die_size/total_die_size_float)*100.0;
+ s->Printf("%7u %8u %2.2f%% %s\n", die_count, die_size, percentage, DW_TAG_value_to_name(pos->first));
+
+ const DwarfAttrStatMap& attr_stats = tag_stat.attr_stats;
+ if (!attr_stats.empty())
+ {
+ typedef set<DwarfAttrStatMap::const_iterator, CompareAttrDIEStatSizes> DwarfAttrStatBySizeMap;
+ DwarfAttrStatBySizeMap attrStatBySizeMap;
+ DwarfAttrStatMap::const_iterator attr_stat_pos;
+ DwarfAttrStatMap::const_iterator attr_stat_pos_end = attr_stats.end();
+ for (attr_stat_pos = attr_stats.begin(); attr_stat_pos != attr_stat_pos_end; ++attr_stat_pos)
+ {
+ attrStatBySizeMap.insert(attr_stat_pos);
+ }
+
+ DwarfAttrStatBySizeMap::const_reverse_iterator attr_size_pos;
+ DwarfAttrStatBySizeMap::const_reverse_iterator attr_size_pos_end = attrStatBySizeMap.rend();
+ for (attr_size_pos = attrStatBySizeMap.rbegin(); attr_size_pos != attr_size_pos_end; ++attr_size_pos)
+ {
+ attr_stat_pos = *attr_size_pos;
+ percentage = ((float)attr_stat_pos->second.byte_size/die_size)*100.0;
+ s->Printf("%7u %8u %2.2f%% %s\n", attr_stat_pos->second.count, attr_stat_pos->second.byte_size, percentage, DW_AT_value_to_name(attr_stat_pos->first));
+ }
+ s->EOL();
+ }
+ }
+
+ s->Printf("-------- -------- -------- -------------------------------------------\n");
+ s->Printf("%7u %8u 100.00% Total for all DIEs\n", total_die_count, total_die_size);
+
+ float total_category_percentages[kNumTagCategories] =
+ {
+ ((float)total_category_sizes[TagCategoryVariable]/total_die_size_float)*100.0,
+ ((float)total_category_sizes[TagCategoryType]/total_die_size_float)*100.0,
+ ((float)total_category_sizes[TagCategoryProgram]/total_die_size_float)*100.0
+ };
+
+ s->EOL();
+ s->Printf("%7u %8u %2.2f%% %s\n", total_category_count[TagCategoryVariable], total_category_sizes[TagCategoryVariable], total_category_percentages[TagCategoryVariable], "Total for variable related DIEs");
+ s->Printf("%7u %8u %2.2f%% %s\n", total_category_count[TagCategoryType], total_category_sizes[TagCategoryType], total_category_percentages[TagCategoryType], "Total for type related DIEs");
+ s->Printf("%7u %8u %2.2f%% %s\n", total_category_count[TagCategoryProgram], total_category_sizes[TagCategoryProgram], total_category_percentages[TagCategoryProgram], "Total for program related DIEs");
+ s->Printf("\n\n");
+}
+
+typedef struct DumpInfo
+{
+ DumpInfo(Stream* init_strm, uint32_t off, uint32_t depth) :
+ strm(init_strm),
+ die_offset(off),
+ recurse_depth(depth),
+ found_depth(UINT_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
+// wether 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().IsSet(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 == UINT_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 != UINT_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);
+ cu_sp->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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
new file mode 100644
index 00000000000..f506a3de6e0
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
@@ -0,0 +1,86 @@
+//===-- 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 liblldb_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 lldb::SharedPtr<DWARFCompileUnit>::Type 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 BuildFunctionAddressRangeTable(DWARFDebugAranges* debug_aranges);
+
+ 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);
+ uint32_t GetNumCompileUnits();
+ 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);
+ 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_EnglishyNames = (1<<2), // Show the DW_TAG, DW_AT and DW_FORM types in more englishy names instead of as DWARF definitions values
+ eDumpFlag_ShowAncestors = (1<<3) // Show all parent DIEs when dumping single DIEs
+ };
+
+
+protected:
+ SymbolFileDWARF* m_dwarf2Data;
+ typedef std::vector<DWARFCompileUnitSP> CompileUnitColl;
+
+ CompileUnitColl m_compile_units;
+
+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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
new file mode 100644
index 00000000000..19eef06d3d1
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -0,0 +1,1929 @@
+//===-- 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/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 "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()
+{
+ m_infos.reserve(20);
+}
+
+DWARFDebugInfoEntry::Attributes::~Attributes()
+{
+}
+
+
+uint32_t
+DWARFDebugInfoEntry::Attributes::FindAttributeIndex(dw_attr_t attr) const
+{
+ std::vector<Info>::const_iterator end = m_infos.end();
+ std::vector<Info>::const_iterator beg = m_infos.begin();
+ std::vector<Info>::const_iterator pos;
+ for (pos = beg; pos != end; ++pos)
+ {
+ if (pos->attr == attr)
+ return std::distance(beg, pos);
+ }
+ return UINT_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) != UINT_MAX;
+}
+
+bool
+DWARFDebugInfoEntry::Attributes::RemoveAttribute(dw_attr_t attr)
+{
+ uint32_t attr_index = FindAttributeIndex(attr);
+ if (attr_index != UINT_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));
+ dw_offset_t offset = DIEOffsetAtIndex(i);
+ return form_value.ExtractValue(dwarf2Data->get_debug_info_data(), &offset, CompileUnitAtIndex(i));
+}
+
+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;
+}
+
+
+//----------------------------------------------------------------------
+// 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,
+ uint32_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();
+ uint32_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;
+
+ dw_uleb128_t abbrCode = debug_info_data.GetULEB128(&offset);
+
+ if (abbrCode)
+ {
+ m_abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration(abbrCode);
+
+ if (m_abbrevDecl)
+ {
+ dw_tag_t tag = m_abbrevDecl->Tag();
+
+ bool isCompileUnitTag = 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 = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ m_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
+ {
+die_extract_indirect_form:
+ 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_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 :
+ {
+// const char *s =
+ debug_info_data.GetCStr(&offset);
+// switch (attr)
+// {
+// case DW_AT_name: m_name = s; break;
+// case DW_AT_MIPS_linkage_name: m_linkage_name = s; break;
+// default: break;
+// }
+ }
+ break;
+
+ // Compile unit address sized values
+ case DW_FORM_addr :
+ case DW_FORM_ref_addr :
+ form_size = cu_addr_size;
+ 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 :
+// switch (attr)
+// {
+// case DW_AT_name:
+// m_name = debug_str_data.PeekCStr(debug_info_data.GetU32(&offset));
+// break;
+// case DW_AT_MIPS_linkage_name:
+// m_linkage_name = debug_str_data.PeekCStr(debug_info_data.GetU32(&offset));
+// break;
+//
+// default:
+ form_size = 4;
+// break;
+// }
+ break;
+
+ case DW_FORM_data4 :
+ case DW_FORM_ref4 :
+ form_size = 4;
+ break;
+
+ // 8 byte values
+ case DW_FORM_data8 :
+ case DW_FORM_ref8 :
+ form_size = 8;
+ break;
+
+ // signed or unsigned LEB 128 values
+ // case DW_FORM_APPLE_db_str:
+ 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);
+ goto die_extract_indirect_form;
+
+ default:
+ *offset_ptr = offset;
+ return false;
+ }
+
+ offset += form_size;
+ }
+ }
+ *offset_ptr = offset;
+ return true;
+ }
+ }
+ else
+ {
+ m_abbrevDecl = NULL;
+ *offset_ptr = offset;
+ return true; // NULL debug tag entry
+ }
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------
+// AppendDependentDIES()
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::AppendDependentDIES
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const bool add_children,
+ DWARFDIECollection& dependent_dies
+) const
+{
+ // Add this object's DIE offset
+ // The line below is the only place that should add a die to the
+ // dependent_dies collection as we have to be careful of recursion!
+ if ( !dependent_dies.Insert(this) )
+ return false; // This DIE already exists in the collection, nothing to do!
+
+ //DEBUG_PRINTF(" dependent_dies.Insert(0x%8.8x)\n", GetOffset());///
+
+ if (m_abbrevDecl)
+ {
+ // Keep adding parent DIE offsets as long as the offsets do not
+ // already exist in the collection
+ const DWARFDebugInfoEntry* die = GetParent();
+ while ( die && die->AppendDependentDIES(dwarf2Data, cu, false, dependent_dies) )
+ die = die->GetParent();
+
+ bool add_non_subprogram_children = false;
+ bool add_children_override = false;
+
+ if (!add_children)
+ {
+ switch (m_abbrevDecl->Tag())
+ {
+ case DW_TAG_array_type: break;
+ case DW_TAG_class_type: add_non_subprogram_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: add_children_override = true; break;
+ case DW_TAG_member: break;
+ case DW_TAG_pointer_type: break;
+ case DW_TAG_reference_type: break;
+ case DW_TAG_compile_unit: break;
+ case DW_TAG_string_type: break;
+ case DW_TAG_structure_type: add_non_subprogram_children = true; break;
+ case DW_TAG_subroutine_type: add_children_override = true; break;
+ case DW_TAG_typedef: break;
+ case DW_TAG_union_type: add_non_subprogram_children = true; break;
+ case DW_TAG_unspecified_parameters: break;
+ case DW_TAG_variant: break;
+ case DW_TAG_common_block: break;
+ case DW_TAG_common_inclusion: break;
+ case DW_TAG_inheritance: break;
+ case DW_TAG_inlined_subroutine: break;
+ case DW_TAG_module: 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: 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: add_children_override = 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: 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: 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;
+ }
+ }
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ // Dump all data in the .debug_info for the attributes
+ const uint32_t numAttributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_offset_t offset = GetOffset();
+ debug_info_data.Skip_LEB128(&offset); // Skip abbreviation code
+
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ m_abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
+ DWARFFormValue form_value(form);
+
+ switch (attr)
+ {
+ // All cases that use refer to another DIE should use this case
+ // without
+ // having to check the FORM of the attribute to tell if it refers to another
+ // DIE
+ case DW_AT_abstract_origin:
+ case DW_AT_import:
+ case DW_AT_discr:
+ case DW_AT_containing_type:
+ case DW_AT_base_types:
+ case DW_AT_friend:
+ case DW_AT_specification:
+ case DW_AT_type:
+ case DW_AT_common_reference:
+ case DW_AT_default_value:
+ {
+ form_value.ExtractValue(debug_info_data, &offset, cu);
+ DWARFCompileUnitSP cu_sp_ptr;
+ const DWARFDebugInfoEntry* ref_die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr);
+ if (ref_die)
+ ref_die->AppendDependentDIES(dwarf2Data, cu_sp_ptr.get(), true, dependent_dies);
+ }
+ break;
+
+ default:
+ if (attr != DW_AT_sibling)
+ {
+ switch (form_value.Form())
+ {
+ case DW_FORM_ref_addr:
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+// Log::WarningVerbose("DWARFDebugInfoEntry::AppendDependentDIES() -- check on this item %s: attr = %s form = %s",
+// DW_TAG_value_to_name(m_abbrevDecl->Tag()),
+// DW_AT_value_to_name(attr),
+// DW_FORM_value_to_name(form));
+ break;
+ }
+ }
+ form_value.SkipValue(debug_info_data, &offset, cu);
+ break;
+ }
+ }
+
+ if (m_abbrevDecl->HasChildren())
+ {
+ const DWARFDebugInfoEntry* child;
+ for (child = GetFirstChild(); child != NULL; child = child->GetSibling())
+ {
+ bool add = add_children || add_children_override;
+
+ if (!add)
+ {
+ if (add_non_subprogram_children)
+ {
+ // add_non_subprogram_children is used for classes and structs
+ // that may contain children that are the member variables that
+ // may have functions as children and whom may add the class or
+ // struct by adding their parent. We don't want to add any
+ // functions though since they may have been optimized out. But
+ // we do need to watch for declarations and keep them.
+ if (child->Tag() == DW_TAG_subprogram)
+ {
+ // Check if this subprogram TAG had a DW_AT_declaration attribute set to 1.
+ // If so we need to include this DIE so that we always have a complete view
+ // of a class definition so debuggers can track down any weak symbols that
+ // may not have had weak definition entries.
+ if (child->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_declaration, 0) == 1)
+ add = true;
+ }
+ else
+ {
+ // Add all other items inside a class/struct
+ add = true;
+ }
+ }
+ else
+ {
+ // We don't need to add this child, only add it if it's a NULL tag
+ add = child->IsNULL();
+ }
+ }
+
+ if (add)
+ child->AppendDependentDIES(dwarf2Data, cu, true, dependent_dies);
+ }
+ }
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------
+// 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 = UINT_MAX;
+ uint32_t b_name_index = UINT_MAX;
+ if (is_decl_index != UINT_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 != UINT_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 != UINT_MAX && b_name_index != UINT_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 = DW_INVALID_ADDRESS;
+ dw_addr_t hi_pc = DW_INVALID_ADDRESS;
+ std::vector<dw_offset_t> die_offsets;
+ if (m_abbrevDecl)
+ {
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+ uint32_t offset = m_offset;
+
+ if (!debug_info_data.ValidOffset(offset))
+ return false;
+
+ // Skip the abbreviation code
+ debug_info_data.Skip_LEB128(&offset);
+
+ const uint32_t numAttributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ m_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:
+ case DW_AT_entry_pc:
+ lo_pc = form_value.Unsigned();
+ break;
+
+ case DW_AT_high_pc:
+ hi_pc = form_value.Unsigned();
+ 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.AddOffset(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:
+ 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, NULL);
+ }
+ 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)
+ {
+ Address base_address(cu->GetBaseAddress(), dwarf2Data->GetObjectFile()->GetSectionList());
+ frame_base->SetOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length, &base_address);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ size_t numRanges = ranges.Size();
+
+ if (numRanges == 0)
+ {
+ if (lo_pc != DW_INVALID_ADDRESS)
+ {
+ if (hi_pc != DW_INVALID_ADDRESS)
+ ranges.AddRange(lo_pc, hi_pc);
+ else
+ ranges.AddRange(lo_pc, lo_pc);
+ }
+ }
+
+ if (ranges.Size() == 0 || (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.Size() > 0;
+}
+
+//----------------------------------------------------------------------
+// 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();
+ uint32_t offset = m_offset;
+ bool english = s->GetFlags().IsSet (DWARFDebugInfo::eDumpFlag_EnglishyNames);
+
+ 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)
+ {
+ if (m_abbrevDecl)
+ {
+ if (english)
+ s->PutCString(DW_TAG_value_to_englishy_name(m_abbrevDecl->Tag()));
+ else
+ s->PutCString(DW_TAG_value_to_name(m_abbrevDecl->Tag()));
+ s->Printf( " [%u] %c\n", abbrCode, m_abbrevDecl->HasChildren() ? '*':' ');
+
+ // Dump all data in the .debug_info for the attributes
+ const uint32_t numAttributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ m_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");
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// 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,
+ uint32_t* offset_ptr,
+ Stream *s,
+ dw_attr_t attr,
+ dw_form_t form
+)
+{
+ bool verbose = s->GetVerbose();
+ bool show_form = s->GetFlags().IsSet(DWARFDebugInfo::eDumpFlag_ShowForm);
+ bool english = s->GetFlags().IsSet(DWARFDebugInfo::eDumpFlag_EnglishyNames);
+ const DataExtractor* debug_str_data = dwarf2Data ? &dwarf2Data->get_debug_str_data() : NULL;
+ if (verbose)
+ s->Offset(*offset_ptr);
+ else
+ s->Printf( " ");
+ s->Indent();
+
+ if (english)
+ s->PutCString(DW_AT_value_to_englishy_name(attr));
+ else
+ s->PutCString(DW_AT_value_to_name(attr));
+
+ if (show_form)
+ {
+ s->Printf( "[%s", english ? DW_FORM_value_to_englishy_name(form) : 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]", english ? DW_FORM_value_to_englishy_name(form_value.Form()) : 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.8x", 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);
+ uint32_t ranges_offset = form_value.Unsigned();
+ dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0;
+ 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,
+ DWARFDebugInfoEntry::Attributes& attributes
+) const
+{
+ if (m_abbrevDecl)
+ {
+ uint32_t offset = GetOffset();
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ // Skip the abbreviation code so we are at the data for the attributes
+ debug_info_data.Skip_LEB128(&offset);
+
+ const uint32_t num_attributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ DWARFFormValue form_value;
+ for (i=0; i<num_attributes; ++i)
+ {
+ m_abbrevDecl->GetAttrAndFormByIndexUnchecked (i, attr, form);
+ attributes.Append(cu, offset, attr, form);
+ 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, attributes);
+ }
+ 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(), attributes);
+ }
+ }
+ }
+ else
+ {
+ assert(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
+{
+ if (m_abbrevDecl)
+ {
+ uint32_t attr_idx = m_abbrevDecl->FindAttributeIndex(attr);
+
+ if (attr_idx != DW_INVALID_INDEX)
+ {
+ uint32_t offset = GetOffset();
+
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ // Skip the abbreviation code so we are at the data for the attributes
+ debug_info_data.Skip_LEB128(&offset);
+
+ uint32_t idx=0;
+ while (idx<attr_idx)
+ DWARFFormValue::SkipValue(m_abbrevDecl->GetFormByIndex(idx++), debug_info_data, &offset, cu);
+
+ const dw_offset_t attr_offset = offset;
+ form_value.SetForm(m_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;
+}
+
+//----------------------------------------------------------------------
+// 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
+ dw_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());
+ 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 (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;
+ 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_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 uint32_t die_offset,
+ Stream *s
+)
+{
+ DWARFDebugInfoEntry die;
+ uint32_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 uint32_t die_offset,
+ Stream *s
+)
+{
+ DWARFDebugInfoEntry die;
+ uint32_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();
+
+ 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;
+}
+
+//----------------------------------------------------------------------
+// BuildAddressRangeTable
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::BuildAddressRangeTable
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges
+) const
+{
+ if (m_abbrevDecl)
+ {
+ dw_tag_t tag = m_abbrevDecl->Tag();
+ if (tag == DW_TAG_subprogram)
+ {
+ dw_addr_t hi_pc = DW_INVALID_ADDRESS;
+ dw_addr_t lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (lo_pc != DW_INVALID_ADDRESS)
+ hi_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (hi_pc != DW_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->InsertRange(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_abbrevDecl)
+ {
+ dw_tag_t tag = m_abbrevDecl->Tag();
+ if (tag == DW_TAG_subprogram)
+ {
+ dw_addr_t hi_pc = DW_INVALID_ADDRESS;
+ dw_addr_t lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (lo_pc != DW_INVALID_ADDRESS)
+ hi_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (hi_pc != DW_INVALID_ADDRESS)
+ {
+ // printf("BuildAddressRangeTable() 0x%8.8x: [0x%16.16llx - 0x%16.16llx)\n", m_offset, lo_pc, hi_pc); // DEBUG ONLY
+ debug_aranges->InsertRange(GetOffset(), lo_pc, hi_pc);
+ }
+ }
+
+ const DWARFDebugInfoEntry* child = GetFirstChild();
+ while (child)
+ {
+ child->BuildFunctionAddressRangeTable(dwarf2Data, cu, debug_aranges);
+ child = child->GetSibling();
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+// 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_abbrevDecl)
+ {
+ bool check_children = false;
+ bool match_addr_range = false;
+ dw_tag_t tag = m_abbrevDecl->Tag();
+ // printf("0x%8.8x: %30s: address = 0x%8.8x - ", m_offset, DW_TAG_value_to_name(tag), address);
+ switch (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, DW_INVALID_ADDRESS);
+ if (lo_pc != DW_INVALID_ADDRESS)
+ {
+ dw_addr_t hi_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (hi_pc != DW_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 (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 subtroutines so we must always search
+ // if there is no valid high and low PC
+ check_children = (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.AddOffset(cu->GetBaseAddress());
+ if (ranges.Lookup(address))
+ {
+ found_address = true;
+ // puts("***MATCH***");
+ switch (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;
+}
+
+
+bool
+DWARFDebugInfoEntry::OffsetLessThan (const DWARFDebugInfoEntry& a, const DWARFDebugInfoEntry& b)
+{
+ return a.GetOffset() < b.GetOffset();
+}
+
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
new file mode 100644
index 00000000000..8340acc427e
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
@@ -0,0 +1,320 @@
+//===-- 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 liblldb_DWARFDebugInfoEntry_h_
+#define liblldb_DWARFDebugInfoEntry_h_
+
+#include "SymbolFileDWARF.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 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;
+ 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(); }
+ uint32_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;
+ };
+ std::vector<Info> 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_abbrevDecl (NULL),
+ m_user_data (NULL)
+ {
+ }
+
+
+ void BuildAddressRangeTable(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges) const;
+
+ void BuildFunctionAddressRangeTable(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges) const;
+
+ bool Extract(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ dw_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,
+ DWARFDebugInfoEntry::Attributes& attrs) const;
+
+ 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_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);
+
+ 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);
+
+ bool AppendDependentDIES(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const bool add_children,
+ DWARFDIECollection& die_offsets) const;
+
+ 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,
+ uint32_t* offset_ptr,
+ lldb_private::Stream *s,
+ dw_attr_t attr,
+ dw_form_t form);
+
+ 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;
+
+
+ dw_tag_t Tag() const { return m_abbrevDecl ? m_abbrevDecl->Tag() : 0; }
+ bool IsNULL() const { return m_abbrevDecl == NULL; }
+ dw_offset_t GetOffset() const { return m_offset; }
+ void SetOffset(dw_offset_t offset) { m_offset = offset; }
+ uint32_t NumAttributes() const { return m_abbrevDecl ? m_abbrevDecl->NumAttributes() : 0; }
+ bool HasChildren() const { return m_abbrevDecl != NULL && m_abbrevDecl->HasChildren(); }
+
+ // 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() ? this + 1 : NULL; }
+ const DWARFDebugInfoEntry* GetFirstChild() const { return HasChildren() ? this + 1 : NULL; }
+
+ 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;
+ }
+ const DWARFAbbreviationDeclaration* GetAbbreviationDeclarationPtr() const { return m_abbrevDecl; }
+
+ void * GetUserData() const { return m_user_data; }
+ void SetUserData(void *d) const { m_user_data = d; }
+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; // How many to add to "this" to get the sibling.
+ const DWARFAbbreviationDeclaration* m_abbrevDecl;
+ mutable void * m_user_data; // Flags for use by the parsers
+};
+
+#endif // liblldb_DWARFDebugInfoEntry_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
new file mode 100644
index 00000000000..2b3f39b24f3
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
@@ -0,0 +1,1410 @@
+//===-- 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/Timer.h"
+
+#include "SymbolFileDWARF.h"
+#include "LogChannelDWARF.h"
+
+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();
+ dw_offset_t offset = 0;
+ LineTable::shared_ptr line_table_sp(new LineTable);
+ while (debug_line_data.ValidOffset(offset))
+ {
+ const uint32_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.16llx %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))
+ {
+ uint32_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)
+{
+ uint32_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.8x: 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%llx)", 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%llx)", 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.8llx)", 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%llx, 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)
+{
+ uint32_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, dw_offset_t* offset_ptr, Prologue* prologue)
+{
+// const uint32_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 dw_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;
+ }
+
+ assert(*offset_ptr == end_prologue_offset);
+ return end_prologue_offset;
+}
+
+bool
+DWARFDebugLine::ParseSupportFiles(const DataExtractor& debug_line_data, const char *cu_comp_dir, dw_offset_t stmt_list, FileSpecList &support_files)
+{
+ uint32_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;
+ 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.
+ fullpath = path;
+ }
+ 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;
+ }
+ FileSpec file_spec(fullpath.c_str());
+ support_files.Append(file_spec);
+ }
+ }
+
+ assert(offset == end_prologue_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,
+ dw_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);
+
+ assert(debug_line_data.ValidOffset(end_offset-1));
+
+ 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
+ dw_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) * minimim_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, uint32_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 = UINT_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 = UINT_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.16llx %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
+ // optmimizations 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 funtion 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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
new file mode 100644
index 00000000000..57b2f159661
--- /dev/null
+++ b/lldb/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 liblldb_DWARFDebugLine_h_
+#define liblldb_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 lldb::SharedPtr<Prologue>::Type 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 lldb::SharedPtr<LineTable>::Type 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 funcation that gets called each time an entry it 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_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, dw_offset_t* offset_ptr, Prologue* prologue);
+ static bool ParseStatementTable(const lldb_private::DataExtractor& debug_line_data, dw_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, uint32_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 // liblldb_DWARFDebugLine_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp
new file mode 100644
index 00000000000..0501da8fe40
--- /dev/null
+++ b/lldb/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, dw_offset_t offset)
+{
+ DWARFDebugMacinfoEntry maninfo_entry;
+ if (macinfo_data.GetByteSize() == 0)
+ {
+ s->PutCString("< EMPTY >\n");
+ return;
+ }
+ if (offset == DW_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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h
new file mode 100644
index 00000000000..e420a5be84e
--- /dev/null
+++ b/lldb/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 liblldb_DWARFDebugLine_h_
+#define SymbolFileDWARF_DWARFDebugLine_h_
+
+#include "SymbolFileDWARF.h"
+
+class DWARFDebugMacinfo
+{
+public:
+ DWARFDebugMacinfo();
+
+ ~DWARFDebugMacinfo();
+
+ static void
+ Dump (lldb_private::Stream *s,
+ const lldb_private::DataExtractor& macinfo_data,
+ dw_offset_t offset = DW_INVALID_OFFSET);
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugLine_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp
new file mode 100644
index 00000000000..c07cec45c2a
--- /dev/null
+++ b/lldb/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: '%s'\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, dw_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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h
new file mode 100644
index 00000000000..85dd6254833
--- /dev/null
+++ b/lldb/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 liblldb_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,
+ dw_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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
new file mode 100644
index 00000000000..93ecaed72c6
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
@@ -0,0 +1,297 @@
+//===-- 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_private;
+
+DWARFDebugPubnames::DWARFDebugPubnames() :
+ m_sets()
+{
+}
+
+bool
+DWARFDebugPubnames::Extract(const DataExtractor& data)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "DWARFDebugPubnames::Extract (byte_size = %zu)",
+ data.GetByteSize());
+ Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES);
+ if (log)
+ log->Printf("DWARFDebugPubnames::Extract (byte_size = %zu)", data.GetByteSize());
+
+ if (data.ValidOffset(0))
+ {
+ uint32_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);
+
+ 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;
+ bool is_variable = false;
+ const size_t num_attributes = die->GetAttributes(dwarf2Data, cu, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+
+ dw_tag_t tag = die->Tag();
+
+ is_variable = tag == DW_TAG_variable;
+
+ 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:
+ 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 dont 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))
+ {
+ if (is_variable)
+ cu->AddGlobal(die);
+ 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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h
new file mode 100644
index 00000000000..7d09bf3b55a
--- /dev/null
+++ b/lldb/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 liblldb_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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp
new file mode 100644
index 00000000000..0421ced55d4
--- /dev/null
+++ b/lldb/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, uint32_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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h
new file mode 100644
index 00000000000..0597e368e1f
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h
@@ -0,0 +1,91 @@
+//===-- 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 liblldb_DWARFDebugPubnamesSet_h_
+#define SymbolFileDWARF_DWARFDebugPubnamesSet_h_
+
+#include "SymbolFileDWARF.h"
+#include <string>
+#include <vector>
+#include <ext/hash_map>
+
+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, uint32_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;
+ typedef __gnu_cxx::hash_multimap<const char*, uint32_t, __gnu_cxx::hash<const char*>, CStringEqualBinaryPredicate> cstr_to_index_mmap;
+ DescriptorColl m_descriptors;
+ mutable cstr_to_index_mmap m_name_to_descriptor_index;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugPubnamesSet_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
new file mode 100644
index 00000000000..62da22855f7
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
@@ -0,0 +1,275 @@
+//===-- 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;
+ dw_offset_t offset = 0;
+ dw_offset_t debug_ranges_offset = offset;
+ while (range_list.Extract(dwarf2Data, &offset))
+ {
+ m_range_map[debug_ranges_offset] = range_list;
+ debug_ranges_offset = offset;
+ }
+}
+
+bool
+DWARFDebugRanges::RangeList::AddRange(dw_addr_t lo_addr, dw_addr_t hi_addr)
+{
+ if (lo_addr <= hi_addr)
+ {
+ Range range(lo_addr, hi_addr);
+ ranges.push_back(range);
+ return true;
+ }
+ return false;
+}
+
+const DWARFDebugRanges::Range*
+DWARFDebugRanges::RangeList::Lookup(dw_addr_t offset) const
+{
+ Range::const_iterator pos = ranges.begin();
+ Range::const_iterator end_pos = ranges.end();
+ for (pos = ranges.begin(); pos != end_pos; ++pos)
+ {
+ if (pos->begin_offset <= offset && offset < pos->end_offset)
+ {
+ return &(*pos);
+ }
+ }
+ return NULL;
+}
+
+size_t
+DWARFDebugRanges::RangeList::Size() const
+{
+ return ranges.size();
+}
+
+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::RangeList::Extract(SymbolFileDWARF* dwarf2Data, uint32_t* offset_ptr)
+{
+ Clear();
+ uint32_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 consits of 32 bits of 1's to be 64 bits
+ // of ones
+ switch (addr_size)
+ {
+ case 2:
+ if (begin == 0xFFFFull)
+ begin = DW_INVALID_ADDRESS;
+ break;
+
+ case 4:
+ if (begin == 0xFFFFFFFFull)
+ begin = DW_INVALID_ADDRESS;
+ break;
+
+ case 8:
+ break;
+
+ default:
+ assert(!"DWARFDebugRanges::RangeList::Extract() unsupported address size.");
+ break;
+ }
+
+ // Filter out empty ranges
+ if (begin != end)
+ ranges.push_back(Range(begin, end));
+ }
+
+ // Make sure we consumed at least something
+ return range_offset != *offset_ptr;
+}
+
+
+dw_addr_t
+DWARFDebugRanges::RangeList::LowestAddress(const dw_addr_t cu_base_addr) const
+{
+ dw_addr_t addr = DW_INVALID_ADDRESS;
+ dw_addr_t curr_base_addr = cu_base_addr;
+ if (!ranges.empty())
+ {
+ Range::const_iterator pos = ranges.begin();
+ Range::const_iterator end_pos = ranges.end();
+ for (pos = ranges.begin(); pos != end_pos; ++pos)
+ {
+ if (pos->begin_offset == DW_INVALID_ADDRESS)
+ curr_base_addr = pos->end_offset;
+ else if (curr_base_addr != DW_INVALID_ADDRESS)
+ {
+ dw_addr_t curr_addr = curr_base_addr + pos->begin_offset;
+ if (addr > curr_addr)
+ addr = curr_addr;
+ }
+ }
+ }
+ return addr;
+}
+
+dw_addr_t
+DWARFDebugRanges::RangeList::HighestAddress(const dw_addr_t cu_base_addr) const
+{
+ dw_addr_t addr = 0;
+ dw_addr_t curr_base_addr = cu_base_addr;
+ if (!ranges.empty())
+ {
+ Range::const_iterator pos = ranges.begin();
+ Range::const_iterator end_pos = ranges.end();
+ for (pos = ranges.begin(); pos != end_pos; ++pos)
+ {
+ if (pos->begin_offset == DW_INVALID_ADDRESS)
+ curr_base_addr = pos->end_offset;
+ else if (curr_base_addr != DW_INVALID_ADDRESS)
+ {
+ dw_addr_t curr_addr = curr_base_addr + pos->end_offset;
+ if (addr < curr_addr)
+ addr = curr_addr;
+ }
+ }
+ }
+ if (addr != 0)
+ return addr;
+ return DW_INVALID_ADDRESS;
+}
+
+
+void
+DWARFDebugRanges::Dump(Stream *s, const DataExtractor& debug_ranges_data, uint32_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 = DW_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 == DW_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/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h
new file mode 100644
index 00000000000..607c3c24a3e
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h
@@ -0,0 +1,89 @@
+//===-- 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 liblldb_DWARFDebugRanges_h_
+#define liblldb_DWARFDebugRanges_h_
+
+#include "SymbolFileDWARF.h"
+#include <map>
+#include <vector>
+
+
+class DWARFDebugRanges
+{
+public:
+
+ //------------------------------------------------------------------
+ // Address range
+ //------------------------------------------------------------------
+ struct Range
+ {
+ Range(dw_addr_t begin = DW_INVALID_ADDRESS, dw_addr_t end = DW_INVALID_ADDRESS) :
+ begin_offset(begin),
+ end_offset(end)
+ {
+ }
+
+ void Clear()
+ {
+ begin_offset = DW_INVALID_ADDRESS;
+ end_offset = DW_INVALID_ADDRESS;
+ }
+
+ dw_addr_t begin_offset;
+ dw_addr_t end_offset;
+
+ typedef std::vector<Range> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ };
+
+ //------------------------------------------------------------------
+ // Collection of ranges
+ //------------------------------------------------------------------
+ struct RangeList
+ {
+ RangeList() :
+ ranges()
+ {
+ }
+
+ bool Extract(SymbolFileDWARF* dwarf2Data, uint32_t* offset_ptr);
+ bool AddRange(dw_addr_t lo_addr, dw_addr_t hi_addr);
+ void Clear()
+ {
+ ranges.clear();
+ }
+
+ dw_addr_t LowestAddress(const dw_addr_t base_addr) const;
+ dw_addr_t HighestAddress(const dw_addr_t base_addr) const;
+ void AddOffset(dw_addr_t offset);
+ void SubtractOffset(dw_addr_t offset);
+ size_t Size() const;
+ const Range* RangeAtIndex(size_t i) const;
+ const Range* Lookup(dw_addr_t offset) const;
+ Range::collection ranges;
+ };
+
+ DWARFDebugRanges();
+ ~DWARFDebugRanges();
+ void Extract(SymbolFileDWARF* dwarf2Data);
+ static void Dump(lldb_private::Stream *s, const lldb_private::DataExtractor& debug_ranges_data, uint32_t* offset_ptr, dw_addr_t cu_base_addr);
+ bool FindRanges(dw_offset_t debug_ranges_offset, DWARFDebugRanges::RangeList& range_list) const;
+
+protected:
+ 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 // liblldb_DWARFDebugRanges_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.c b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.c
new file mode 100644
index 00000000000..fe487f9b792
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.c
@@ -0,0 +1,2224 @@
+//===-- 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 <stdio.h>
+
+#define DW_TAG_PREFIX "TAG_"
+#define DW_AT_PREFIX " AT_"
+#define DW_FORM_PREFIX "FORM_"
+
+/* [7.5.4] Figure 16 "Tag Encodings" (pp. 125-127) in DWARFv3 draft 8 */
+
+const char *
+DW_TAG_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0000: return DW_TAG_PREFIX "NULL";
+ case 0x0001: return DW_TAG_PREFIX "array_type";
+ case 0x0002: return DW_TAG_PREFIX "class_type";
+ case 0x0003: return DW_TAG_PREFIX "entry_point";
+ case 0x0004: return DW_TAG_PREFIX "enumeration_type";
+ case 0x0005: return DW_TAG_PREFIX "formal_parameter";
+ case 0x0008: return DW_TAG_PREFIX "imported_declaration";
+ case 0x000a: return DW_TAG_PREFIX "label";
+ case 0x000b: return DW_TAG_PREFIX "lexical_block";
+ case 0x000d: return DW_TAG_PREFIX "member";
+ case 0x000f: return DW_TAG_PREFIX "pointer_type";
+ case 0x0010: return DW_TAG_PREFIX "reference_type";
+ case 0x0011: return DW_TAG_PREFIX "compile_unit";
+ case 0x0012: return DW_TAG_PREFIX "string_type";
+ case 0x0013: return DW_TAG_PREFIX "structure_type";
+ case 0x0015: return DW_TAG_PREFIX "subroutine_type";
+ case 0x0016: return DW_TAG_PREFIX "typedef";
+ case 0x0017: return DW_TAG_PREFIX "union_type";
+ case 0x0018: return DW_TAG_PREFIX "unspecified_parameters";
+ case 0x0019: return DW_TAG_PREFIX "variant";
+ case 0x001a: return DW_TAG_PREFIX "common_block";
+ case 0x001b: return DW_TAG_PREFIX "common_inclusion";
+ case 0x001c: return DW_TAG_PREFIX "inheritance";
+ case 0x001d: return DW_TAG_PREFIX "inlined_subroutine";
+ case 0x001e: return DW_TAG_PREFIX "module";
+ case 0x001f: return DW_TAG_PREFIX "ptr_to_member_type";
+ case 0x0020: return DW_TAG_PREFIX "set_type";
+ case 0x0021: return DW_TAG_PREFIX "subrange_type";
+ case 0x0022: return DW_TAG_PREFIX "with_stmt";
+ case 0x0023: return DW_TAG_PREFIX "access_declaration";
+ case 0x0024: return DW_TAG_PREFIX "base_type";
+ case 0x0025: return DW_TAG_PREFIX "catch_block";
+ case 0x0026: return DW_TAG_PREFIX "const_type";
+ case 0x0027: return DW_TAG_PREFIX "constant";
+ case 0x0028: return DW_TAG_PREFIX "enumerator";
+ case 0x0029: return DW_TAG_PREFIX "file_type";
+ case 0x002a: return DW_TAG_PREFIX "friend";
+ case 0x002b: return DW_TAG_PREFIX "namelist";
+ case 0x002c: return DW_TAG_PREFIX "namelist_item";
+ case 0x002d: return DW_TAG_PREFIX "packed_type";
+ case 0x002e: return DW_TAG_PREFIX "subprogram";
+ case 0x002f: return DW_TAG_PREFIX "template_type_parameter";
+ case 0x0030: return DW_TAG_PREFIX "template_value_parameter";
+ case 0x0031: return DW_TAG_PREFIX "thrown_type";
+ case 0x0032: return DW_TAG_PREFIX "try_block";
+ case 0x0033: return DW_TAG_PREFIX "variant_part";
+ case 0x0034: return DW_TAG_PREFIX "variable";
+ case 0x0035: return DW_TAG_PREFIX "volatile_type";
+ case 0x0036: return DW_TAG_PREFIX "dwarf_procedure";
+ case 0x0037: return DW_TAG_PREFIX "restrict_type";
+ case 0x0038: return DW_TAG_PREFIX "interface_type";
+ case 0x0039: return DW_TAG_PREFIX "namespace";
+ case 0x003a: return DW_TAG_PREFIX "imported_module";
+ case 0x003b: return DW_TAG_PREFIX "unspecified_type";
+ case 0x003c: return DW_TAG_PREFIX "partial_unit";
+ case 0x003d: return DW_TAG_PREFIX "imported_unit";
+// case 0x003d: return DW_TAG_PREFIX "condition";
+ case 0x0040: return DW_TAG_PREFIX "shared_type";
+ case 0x4080: return DW_TAG_PREFIX "lo_user";
+ case 0xffff: return DW_TAG_PREFIX "hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_TAG constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_TAG_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0001: return "array type";
+ case 0x0002: return "class type";
+ case 0x0003: return "entry point";
+ case 0x0004: return "enumeration type";
+ case 0x0005: return "formal parameter";
+ case 0x0008: return "imported declaration";
+ case 0x000a: return "label";
+ case 0x000b: return "lexical block";
+ case 0x000d: return "member";
+ case 0x000f: return "pointer type";
+ case 0x0010: return "reference type";
+ case 0x0011: return "file";
+ case 0x0012: return "string type";
+ case 0x0013: return "structure type";
+ case 0x0015: return "subroutine type";
+ case 0x0016: return "typedef";
+ case 0x0017: return "union type";
+ case 0x0018: return "unspecified parameters";
+ case 0x0019: return "variant";
+ case 0x001a: return "common block";
+ case 0x001b: return "common inclusion";
+ case 0x001c: return "inheritance";
+ case 0x001d: return "inlined subroutine";
+ case 0x001e: return "module";
+ case 0x001f: return "ptr to member type";
+ case 0x0020: return "set type";
+ case 0x0021: return "subrange type";
+ case 0x0022: return "with stmt";
+ case 0x0023: return "access declaration";
+ case 0x0024: return "base type";
+ case 0x0025: return "catch block";
+ case 0x0026: return "const type";
+ case 0x0027: return "constant";
+ case 0x0028: return "enumerator";
+ case 0x0029: return "file type";
+ case 0x002a: return "friend";
+ case 0x002b: return "namelist";
+ case 0x002c: return "namelist item";
+ case 0x002d: return "packed type";
+ case 0x002e: return "function";
+ case 0x002f: return "template type parameter";
+ case 0x0030: return "template value parameter";
+ case 0x0031: return "thrown type";
+ case 0x0032: return "try block";
+ case 0x0033: return "variant part";
+ case 0x0034: return "variable";
+ case 0x0035: return "volatile type";
+ case 0x0036: return "dwarf procedure";
+ case 0x0037: return "restrict type";
+ case 0x0038: return "interface type";
+ case 0x0039: return "namespace";
+ case 0x003a: return "imported module";
+ case 0x003b: return "unspecified type";
+ case 0x003c: return "partial unit";
+ case 0x003d: return "imported unit";
+// case 0x003d: return "condition";
+ case 0x0040: return "shared type";
+ case 0x4080: return "lo user";
+ case 0xffff: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_TAG constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_TAG_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0001: return 0;
+ case 0x0002: return 0;
+ case 0x0003: return 0;
+ case 0x0004: return 0;
+ case 0x0005: return 0;
+ case 0x0008: return 0;
+ case 0x000a: return 0;
+ case 0x000b: return 0;
+ case 0x000d: return 0;
+ case 0x000f: return 0;
+ case 0x0010: return 0;
+ case 0x0011: return 0;
+ case 0x0012: return 0;
+ case 0x0013: return 0;
+ case 0x0015: return 0;
+ case 0x0016: return 0;
+ case 0x0017: return 0;
+ case 0x0018: return 0;
+ case 0x0019: return 0;
+ case 0x001a: return 0;
+ case 0x001b: return 0;
+ case 0x001c: return 0;
+ case 0x001d: return 0;
+ case 0x001e: return 0;
+ case 0x001f: return 0;
+ case 0x0020: return 0;
+ case 0x0021: return 0;
+ case 0x0022: return 0;
+ case 0x0023: return 0;
+ case 0x0024: return 0;
+ case 0x0025: return 0;
+ case 0x0026: return 0;
+ case 0x0027: return 0;
+ case 0x0028: return 0;
+ case 0x0029: return 0;
+ case 0x002a: return 0;
+ case 0x002b: return 0;
+ case 0x002c: return 0;
+ case 0x002d: return 0;
+ case 0x002e: return 0;
+ case 0x002f: return 0;
+ case 0x0030: return 0;
+ case 0x0031: return 0;
+ case 0x0032: return 0;
+ case 0x0033: return 0;
+ case 0x0034: return 0;
+ case 0x0035: return 0;
+ case 0x0036: return DRC_DWARFv3;
+ case 0x0037: return DRC_DWARFv3;
+ case 0x0038: return DRC_DWARFv3;
+ case 0x0039: return DRC_DWARFv3;
+ case 0x003a: return DRC_DWARFv3;
+ case 0x003b: return DRC_DWARFv3;
+ case 0x003c: return DRC_DWARFv3;
+ case 0x003d: return DRC_DWARFv3;
+// case 0x003d: return DRC_DWARFv3;
+ case 0x0040: return DRC_DWARFv3;
+ case 0x4080: return 0;
+ case 0xffff: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.5.4] Figure 17 "Child determination encodings" (p. 128) in DWARFv3 draft 8 */
+
+const char *
+DW_CHILDREN_value_to_name (uint8_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_CHILDREN_no";
+ case 0x1: return "DW_CHILDREN_yes";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_CHILDREN constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_CHILDREN_value_to_englishy_name (uint8_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "no";
+ case 0x1: return "yes";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_CHILDREN constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_CHILDREN_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ case 0x1: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.5.4] Figure 18 "Attribute encodings" (pp. 129-132) in DWARFv3 draft 8 */
+
+const char *
+DW_AT_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0001: return DW_AT_PREFIX "sibling";
+ case 0x0002: return DW_AT_PREFIX "location";
+ case 0x0003: return DW_AT_PREFIX "name";
+ case 0x0009: return DW_AT_PREFIX "ordering";
+ case 0x000b: return DW_AT_PREFIX "byte_size";
+ case 0x000c: return DW_AT_PREFIX "bit_offset";
+ case 0x000d: return DW_AT_PREFIX "bit_size";
+ case 0x0010: return DW_AT_PREFIX "stmt_list";
+ case 0x0011: return DW_AT_PREFIX "low_pc";
+ case 0x0012: return DW_AT_PREFIX "high_pc";
+ case 0x0013: return DW_AT_PREFIX "language";
+ case 0x0015: return DW_AT_PREFIX "discr";
+ case 0x0016: return DW_AT_PREFIX "discr_value";
+ case 0x0017: return DW_AT_PREFIX "visibility";
+ case 0x0018: return DW_AT_PREFIX "import";
+ case 0x0019: return DW_AT_PREFIX "string_length";
+ case 0x001a: return DW_AT_PREFIX "common_reference";
+ case 0x001b: return DW_AT_PREFIX "comp_dir";
+ case 0x001c: return DW_AT_PREFIX "const_value";
+ case 0x001d: return DW_AT_PREFIX "containing_type";
+ case 0x001e: return DW_AT_PREFIX "default_value";
+ case 0x0020: return DW_AT_PREFIX "inline";
+ case 0x0021: return DW_AT_PREFIX "is_optional";
+ case 0x0022: return DW_AT_PREFIX "lower_bound";
+ case 0x0025: return DW_AT_PREFIX "producer";
+ case 0x0027: return DW_AT_PREFIX "prototyped";
+ case 0x002a: return DW_AT_PREFIX "return_addr";
+ case 0x002c: return DW_AT_PREFIX "start_scope";
+ case 0x002e: return DW_AT_PREFIX "bit_stride";
+ case 0x002f: return DW_AT_PREFIX "upper_bound";
+ case 0x0031: return DW_AT_PREFIX "abstract_origin";
+ case 0x0032: return DW_AT_PREFIX "accessibility";
+ case 0x0033: return DW_AT_PREFIX "address_class";
+ case 0x0034: return DW_AT_PREFIX "artificial";
+ case 0x0035: return DW_AT_PREFIX "base_types";
+ case 0x0036: return DW_AT_PREFIX "calling_convention";
+ case 0x0037: return DW_AT_PREFIX "count";
+ case 0x0038: return DW_AT_PREFIX "data_member_location";
+ case 0x0039: return DW_AT_PREFIX "decl_column";
+ case 0x003a: return DW_AT_PREFIX "decl_file";
+ case 0x003b: return DW_AT_PREFIX "decl_line";
+ case 0x003c: return DW_AT_PREFIX "declaration";
+ case 0x003d: return DW_AT_PREFIX "discr_list";
+ case 0x003e: return DW_AT_PREFIX "encoding";
+ case 0x003f: return DW_AT_PREFIX "external";
+ case 0x0040: return DW_AT_PREFIX "frame_base";
+ case 0x0041: return DW_AT_PREFIX "friend";
+ case 0x0042: return DW_AT_PREFIX "identifier_case";
+ case 0x0043: return DW_AT_PREFIX "macro_info";
+ case 0x0044: return DW_AT_PREFIX "namelist_item";
+ case 0x0045: return DW_AT_PREFIX "priority";
+ case 0x0046: return DW_AT_PREFIX "segment";
+ case 0x0047: return DW_AT_PREFIX "specification";
+ case 0x0048: return DW_AT_PREFIX "static_link";
+ case 0x0049: return DW_AT_PREFIX "type";
+ case 0x004a: return DW_AT_PREFIX "use_location";
+ case 0x004b: return DW_AT_PREFIX "variable_parameter";
+ case 0x004c: return DW_AT_PREFIX "virtuality";
+ case 0x004d: return DW_AT_PREFIX "vtable_elem_location";
+ case 0x004e: return DW_AT_PREFIX "allocated";
+ case 0x004f: return DW_AT_PREFIX "associated";
+ case 0x0050: return DW_AT_PREFIX "data_location";
+ case 0x0051: return DW_AT_PREFIX "byte_stride";
+ case 0x0052: return DW_AT_PREFIX "entry_pc";
+ case 0x0053: return DW_AT_PREFIX "use_UTF8";
+ case 0x0054: return DW_AT_PREFIX "extension";
+ case 0x0055: return DW_AT_PREFIX "ranges";
+ case 0x0056: return DW_AT_PREFIX "trampoline";
+ case 0x0057: return DW_AT_PREFIX "call_column";
+ case 0x0058: return DW_AT_PREFIX "call_file";
+ case 0x0059: return DW_AT_PREFIX "call_line";
+ case 0x005a: return DW_AT_PREFIX "description";
+ case 0x005b: return DW_AT_PREFIX "binary_scale";
+ case 0x005c: return DW_AT_PREFIX "decimal_scale";
+ case 0x005d: return DW_AT_PREFIX "small";
+ case 0x005e: return DW_AT_PREFIX "decimal_sign";
+ case 0x005f: return DW_AT_PREFIX "digit_count";
+ case 0x0060: return DW_AT_PREFIX "picture_string";
+ case 0x0061: return DW_AT_PREFIX "mutable";
+ case 0x0062: return DW_AT_PREFIX "threads_scaled";
+ case 0x0063: return DW_AT_PREFIX "explicit";
+ case 0x0064: return DW_AT_PREFIX "object_pointer";
+ case 0x0065: return DW_AT_PREFIX "endianity";
+ case 0x0066: return DW_AT_PREFIX "elemental";
+ case 0x0067: return DW_AT_PREFIX "pure";
+ case 0x0068: return DW_AT_PREFIX "recursive";
+ case 0x2000: return DW_AT_PREFIX "lo_user";
+ case 0x3fff: return DW_AT_PREFIX "hi_user";
+ case 0x2001: return DW_AT_PREFIX "MIPS_fde";
+ case 0x2002: return DW_AT_PREFIX "MIPS_loop_begin";
+ case 0x2003: return DW_AT_PREFIX "MIPS_tail_loop_begin";
+ case 0x2004: return DW_AT_PREFIX "MIPS_epilog_begin";
+ case 0x2005: return DW_AT_PREFIX "MIPS_loop_unroll_factor";
+ case 0x2006: return DW_AT_PREFIX "MIPS_software_pipeline_depth";
+ case 0x2007: return DW_AT_PREFIX "MIPS_linkage_name";
+ case 0x2008: return DW_AT_PREFIX "MIPS_stride";
+ case 0x2009: return DW_AT_PREFIX "MIPS_abstract_name";
+ case 0x200a: return DW_AT_PREFIX "MIPS_clone_origin";
+ case 0x200b: return DW_AT_PREFIX "MIPS_has_inlines";
+ case 0x2101: return DW_AT_PREFIX "sf_names";
+ case 0x2102: return DW_AT_PREFIX "src_info";
+ case 0x2103: return DW_AT_PREFIX "mac_info";
+ case 0x2104: return DW_AT_PREFIX "src_coords";
+ case 0x2105: return DW_AT_PREFIX "body_begin";
+ case 0x2106: return DW_AT_PREFIX "body_end";
+ case 0x2107: return DW_AT_PREFIX "GNU_vector";
+ case 0x2501: return DW_AT_PREFIX "APPLE_repository_file";
+ case 0x2502: return DW_AT_PREFIX "APPLE_repository_type";
+ case 0x2503: return DW_AT_PREFIX "APPLE_repository_name";
+ case 0x2504: return DW_AT_PREFIX "APPLE_repository_specification";
+ case 0x2505: return DW_AT_PREFIX "APPLE_repository_import";
+ case 0x2506: return DW_AT_PREFIX "APPLE_repository_abstract_origin";
+ case DW_AT_APPLE_flags: return DW_AT_PREFIX "APPLE_flags";
+ case DW_AT_APPLE_optimized: return DW_AT_PREFIX "APPLE_optimized";
+ case DW_AT_APPLE_isa: return DW_AT_PREFIX "APPLE_isa";
+ case DW_AT_APPLE_block: return DW_AT_PREFIX "APPLE_block";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_AT constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_AT_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0001: return "sibling";
+ case 0x0002: return "location";
+ case 0x0003: return "name";
+ case 0x0009: return "ordering";
+ case 0x000b: return "byte size";
+ case 0x000c: return "bit offset";
+ case 0x000d: return "bit size";
+ case 0x0010: return "stmt list";
+ case 0x0011: return "low pc";
+ case 0x0012: return "high pc";
+ case 0x0013: return "language";
+ case 0x0015: return "discr";
+ case 0x0016: return "discr value";
+ case 0x0017: return "visibility";
+ case 0x0018: return "import";
+ case 0x0019: return "string length";
+ case 0x001a: return "common reference";
+ case 0x001b: return "comp dir";
+ case 0x001c: return "const value";
+ case 0x001d: return "containing type";
+ case 0x001e: return "default value";
+ case 0x0020: return "inline";
+ case 0x0021: return "is optional";
+ case 0x0022: return "lower bound";
+ case 0x0025: return "producer";
+ case 0x0027: return "prototyped";
+ case 0x002a: return "return addr";
+ case 0x002c: return "start scope";
+ case 0x002e: return "bit stride";
+ case 0x002f: return "upper bound";
+ case 0x0031: return "abstract origin";
+ case 0x0032: return "accessibility";
+ case 0x0033: return "address class";
+ case 0x0034: return "artificial";
+ case 0x0035: return "base types";
+ case 0x0036: return "calling convention";
+ case 0x0037: return "count";
+ case 0x0038: return "data member location";
+ case 0x0039: return "decl column";
+ case 0x003a: return "decl file";
+ case 0x003b: return "decl line";
+ case 0x003c: return "declaration";
+ case 0x003d: return "discr list";
+ case 0x003e: return "encoding";
+ case 0x003f: return "external";
+ case 0x0040: return "frame base";
+ case 0x0041: return "friend";
+ case 0x0042: return "identifier case";
+ case 0x0043: return "macro info";
+ case 0x0044: return "namelist item";
+ case 0x0045: return "priority";
+ case 0x0046: return "segment";
+ case 0x0047: return "specification";
+ case 0x0048: return "static link";
+ case 0x0049: return "type";
+ case 0x004a: return "use location";
+ case 0x004b: return "variable parameter";
+ case 0x004c: return "virtuality";
+ case 0x004d: return "vtable elem location";
+ case 0x004e: return "allocated";
+ case 0x004f: return "associated";
+ case 0x0050: return "data location";
+ case 0x0051: return "byte stride";
+ case 0x0052: return "entry pc";
+ case 0x0053: return "use UTF8";
+ case 0x0054: return "extension";
+ case 0x0055: return "ranges";
+ case 0x0056: return "trampoline";
+ case 0x0057: return "call column";
+ case 0x0058: return "call file";
+ case 0x0059: return "call line";
+ case 0x005a: return "description";
+ case 0x005b: return "binary scale";
+ case 0x005c: return "decimal scale";
+ case 0x005d: return "small";
+ case 0x005e: return "decimal sign";
+ case 0x005f: return "digit count";
+ case 0x0060: return "picture string";
+ case 0x0061: return "mutable";
+ case 0x0062: return "threads scaled";
+ case 0x0063: return "explicit";
+ case 0x0064: return "object pointer";
+ case 0x0065: return "endianity";
+ case 0x0066: return "elemental";
+ case 0x0067: return "pure";
+ case 0x0068: return "recursive";
+ case 0x2000: return "lo user";
+ case 0x3fff: return "hi user";
+ case 0x2001: return "MIPS fde";
+ case 0x2002: return "MIPS loop begin";
+ case 0x2003: return "MIPS tail loop begin";
+ case 0x2004: return "MIPS epilog begin";
+ case 0x2005: return "MIPS loop unroll factor";
+ case 0x2006: return "MIPS software pipeline depth";
+ case 0x2007: return "MIPS linkage name";
+ case 0x2008: return "MIPS stride";
+ case 0x2009: return "MIPS abstract name";
+ case 0x200a: return "MIPS clone origin";
+ case 0x200b: return "MIPS has inlines";
+ case 0x2101: return "source file names";
+ case 0x2102: return "source info";
+ case 0x2103: return "macro info";
+ case 0x2104: return "source coordinates";
+ case 0x2105: return "body begin";
+ case 0x2106: return "body end";
+ case 0x2107: return "GNU vector";
+ case 0x2501: return "repository file";
+ case 0x2502: return "repository type";
+ case 0x2503: return "repository name";
+ case 0x2504: return "repository specification";
+ case 0x2505: return "repository import";
+ case 0x2506: return "repository abstract origin";
+ case DW_AT_APPLE_flags: return "Apple gcc compiler flags";
+ case DW_AT_APPLE_optimized: return "APPLE optimized";
+ case DW_AT_APPLE_isa: return "APPLE instruction set architecture";
+ case DW_AT_APPLE_block: return "APPLE block";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_AT constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_AT_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0001: return DRC_REFERENCE;
+ case 0x0002: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x0003: return DRC_STRING;
+ case 0x0009: return DRC_CONSTANT;
+ case 0x000b: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE;
+ case 0x000c: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE;
+ case 0x000d: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE;
+ case 0x0010: return DRC_LINEPTR;
+ case 0x0011: return DRC_ADDRESS;
+ case 0x0012: return DRC_ADDRESS;
+ case 0x0013: return DRC_CONSTANT;
+ case 0x0015: return DRC_REFERENCE;
+ case 0x0016: return DRC_CONSTANT;
+ case 0x0017: return DRC_CONSTANT;
+ case 0x0018: return DRC_REFERENCE;
+ case 0x0019: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x001a: return DRC_REFERENCE;
+ case 0x001b: return DRC_STRING;
+ case 0x001c: return DRC_BLOCK | DRC_CONSTANT | DRC_STRING;
+ case 0x001d: return DRC_REFERENCE;
+ case 0x001e: return DRC_REFERENCE;
+ case 0x0020: return DRC_CONSTANT;
+ case 0x0021: return DRC_FLAG;
+ case 0x0022: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE;
+ case 0x0025: return DRC_STRING;
+ case 0x0027: return DRC_FLAG;
+ case 0x002a: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x002c: return DRC_CONSTANT;
+ case 0x002e: return DRC_CONSTANT;
+ case 0x002f: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE;
+ case 0x0031: return DRC_REFERENCE;
+ case 0x0032: return DRC_CONSTANT;
+ case 0x0033: return DRC_CONSTANT;
+ case 0x0034: return DRC_FLAG;
+ case 0x0035: return DRC_REFERENCE;
+ case 0x0036: return DRC_CONSTANT;
+ case 0x0037: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE;
+ case 0x0038: return DRC_BLOCK | DRC_CONSTANT | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x0039: return DRC_CONSTANT;
+ case 0x003a: return DRC_CONSTANT;
+ case 0x003b: return DRC_CONSTANT;
+ case 0x003c: return DRC_FLAG;
+ case 0x003d: return DRC_BLOCK;
+ case 0x003e: return DRC_CONSTANT;
+ case 0x003f: return DRC_FLAG;
+ case 0x0040: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x0041: return DRC_REFERENCE;
+ case 0x0042: return DRC_CONSTANT;
+ case 0x0043: return DRC_MACPTR;
+ case 0x0044: return DRC_BLOCK;
+ case 0x0045: return DRC_REFERENCE;
+ case 0x0046: return DRC_BLOCK | DRC_CONSTANT;
+ case 0x0047: return DRC_REFERENCE;
+ case 0x0048: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x0049: return DRC_REFERENCE;
+ case 0x004a: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x004b: return DRC_FLAG;
+ case 0x004c: return DRC_CONSTANT;
+ case 0x004d: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR;
+ case 0x004e: return DRC_BLOCK | DRC_CONSTANT | DRC_DWARFv3 | DRC_REFERENCE;
+ case 0x004f: return DRC_BLOCK | DRC_CONSTANT | DRC_DWARFv3 | DRC_REFERENCE;
+ case 0x0050: return DRC_BLOCK | DRC_DWARFv3;
+ case 0x0051: return DRC_BLOCK | DRC_CONSTANT | DRC_DWARFv3 | DRC_REFERENCE;
+ case 0x0052: return DRC_ADDRESS | DRC_DWARFv3;
+ case 0x0053: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x0054: return DRC_DWARFv3 | DRC_REFERENCE;
+ case 0x0055: return DRC_DWARFv3 | DRC_RANGELISTPTR;
+ case 0x0056: return DRC_ADDRESS | DRC_DWARFv3 | DRC_FLAG | DRC_REFERENCE | DRC_STRING;
+ case 0x0057: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x0058: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x0059: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x005a: return DRC_DWARFv3 | DRC_STRING;
+ case 0x005b: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x005c: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x005d: return DRC_DWARFv3 | DRC_REFERENCE;
+ case 0x005e: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x005f: return DRC_CONSTANT | DRC_DWARFv3;
+ case 0x0060: return DRC_DWARFv3 | DRC_STRING;
+ case 0x0061: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x0062: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x0063: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x0064: return DRC_DWARFv3 | DRC_REFERENCE;
+ case 0x0065: return DRC_0x65 | DRC_CONSTANT | DRC_DWARFv3;
+ case 0x0066: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x0067: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x0068: return DRC_DWARFv3 | DRC_FLAG;
+ case 0x2000: return 0;
+ case 0x3fff: return 0;
+ case 0x2001: return DRC_VENDOR_MIPS;
+ case 0x2002: return DRC_VENDOR_MIPS;
+ case 0x2003: return DRC_VENDOR_MIPS;
+ case 0x2004: return DRC_VENDOR_MIPS;
+ case 0x2005: return DRC_VENDOR_MIPS;
+ case 0x2006: return DRC_VENDOR_MIPS;
+ case 0x2007: return DRC_STRING | DRC_VENDOR_MIPS;
+ case 0x2008: return DRC_VENDOR_MIPS;
+ case 0x2009: return DRC_VENDOR_MIPS;
+ case 0x200a: return DRC_VENDOR_MIPS;
+ case 0x200b: return DRC_VENDOR_MIPS;
+ default: return 0;
+ }
+}
+
+/* [7.5.4] Figure 19 "Attribute form encodings" (pp. 133-134) in DWARFv3 draft 8 */
+
+const char *
+DW_FORM_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return DW_FORM_PREFIX "addr";
+ case 0x03: return DW_FORM_PREFIX "block2";
+ case 0x04: return DW_FORM_PREFIX "block4";
+ case 0x05: return DW_FORM_PREFIX "data2";
+ case 0x06: return DW_FORM_PREFIX "data4";
+ case 0x07: return DW_FORM_PREFIX "data8";
+ case 0x08: return DW_FORM_PREFIX "string";
+ case 0x09: return DW_FORM_PREFIX "block";
+ case 0x0a: return DW_FORM_PREFIX "block1";
+ case 0x0b: return DW_FORM_PREFIX "data1";
+ case 0x0c: return DW_FORM_PREFIX "flag";
+ case 0x0d: return DW_FORM_PREFIX "sdata";
+ case 0x0e: return DW_FORM_PREFIX "strp";
+ case 0x0f: return DW_FORM_PREFIX "udata";
+ case 0x10: return DW_FORM_PREFIX "ref_addr";
+ case 0x11: return DW_FORM_PREFIX "ref1";
+ case 0x12: return DW_FORM_PREFIX "ref2";
+ case 0x13: return DW_FORM_PREFIX "ref4";
+ case 0x14: return DW_FORM_PREFIX "ref8";
+ case 0x15: return DW_FORM_PREFIX "ref_udata";
+ case 0x16: return DW_FORM_PREFIX "indirect";
+// case DW_FORM_APPLE_db_str: return DW_FORM_PREFIX "APPLE_db_str";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_FORM constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_FORM_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "addr";
+ case 0x03: return "block2";
+ case 0x04: return "block4";
+ case 0x05: return "data2";
+ case 0x06: return "data4";
+ case 0x07: return "data8";
+ case 0x08: return "string";
+ case 0x09: return "block";
+ case 0x0a: return "block1";
+ case 0x0b: return "data1";
+ case 0x0c: return "flag";
+ case 0x0d: return "sdata";
+ case 0x0e: return "strp";
+ case 0x0f: return "udata";
+ case 0x10: return "ref addr";
+ case 0x11: return "ref1";
+ case 0x12: return "ref2";
+ case 0x13: return "ref4";
+ case 0x14: return "ref8";
+ case 0x15: return "ref udata";
+ case 0x16: return "indirect";
+// case DW_FORM_APPLE_db_str: return "repository str";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_FORM constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_FORM_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x01: return DRC_ADDRESS;
+ case 0x03: return DRC_BLOCK | DRC_LOCEXPR;
+ case 0x04: return DRC_BLOCK | DRC_LOCEXPR;
+ case 0x05: return DRC_CONSTANT;
+ case 0x06: return DRC_CONSTANT | DRC_LINEPTR | DRC_LOCLISTPTR | DRC_MACPTR | DRC_RANGELISTPTR;
+ case 0x07: return DRC_CONSTANT | DRC_LINEPTR | DRC_LOCLISTPTR | DRC_MACPTR | DRC_RANGELISTPTR;
+ case 0x08: return DRC_STRING;
+ case 0x09: return DRC_BLOCK | DRC_LOCEXPR;
+ case 0x0a: return DRC_BLOCK | DRC_LOCEXPR;
+ case 0x0b: return DRC_CONSTANT;
+ case 0x0c: return DRC_FLAG;
+ case 0x0d: return DRC_CONSTANT;
+ case 0x0e: return DRC_STRING;
+ case 0x0f: return DRC_CONSTANT;
+ case 0x10: return DRC_REFERENCE;
+ case 0x11: return DRC_REFERENCE;
+ case 0x12: return DRC_REFERENCE;
+ case 0x13: return DRC_REFERENCE;
+ case 0x14: return DRC_REFERENCE;
+ case 0x15: return DRC_REFERENCE;
+ case 0x16: return DRC_INDIRECT_SPECIAL;
+ default: return 0;
+ }
+}
+
+/* [7.7.1] Figure 22 "DWARF operation encodings" (pp. 136-139) in DWARFv3 draft 8 */
+
+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 0xf0: return "DW_OP_APPLE_uninit";
+ case 0xe0: return "DW_OP_lo_user";
+ case 0xff: return "DW_OP_hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_OP constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_OP_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x03: return "addr";
+ case 0x06: return "deref";
+ case 0x08: return "const1u";
+ case 0x09: return "const1s";
+ case 0x0a: return "const2u";
+ case 0x0b: return "const2s";
+ case 0x0c: return "const4u";
+ case 0x0d: return "const4s";
+ case 0x0e: return "const8u";
+ case 0x0f: return "const8s";
+ case 0x10: return "constu";
+ case 0x11: return "consts";
+ case 0x12: return "dup";
+ case 0x13: return "drop";
+ case 0x14: return "over";
+ case 0x15: return "pick";
+ case 0x16: return "swap";
+ case 0x17: return "rot";
+ case 0x18: return "xderef";
+ case 0x19: return "abs";
+ case 0x1a: return "and";
+ case 0x1b: return "div";
+ case 0x1c: return "minus";
+ case 0x1d: return "mod";
+ case 0x1e: return "mul";
+ case 0x1f: return "neg";
+ case 0x20: return "not";
+ case 0x21: return "or";
+ case 0x22: return "plus";
+ case 0x23: return "plus uconst";
+ case 0x24: return "shl";
+ case 0x25: return "shr";
+ case 0x26: return "shra";
+ case 0x27: return "xor";
+ case 0x2f: return "skip";
+ case 0x28: return "bra";
+ case 0x29: return "eq";
+ case 0x2a: return "ge";
+ case 0x2b: return "gt";
+ case 0x2c: return "le";
+ case 0x2d: return "lt";
+ case 0x2e: return "ne";
+ case 0x30: return "lit0";
+ case 0x31: return "lit1";
+ case 0x32: return "lit2";
+ case 0x33: return "lit3";
+ case 0x34: return "lit4";
+ case 0x35: return "lit5";
+ case 0x36: return "lit6";
+ case 0x37: return "lit7";
+ case 0x38: return "lit8";
+ case 0x39: return "lit9";
+ case 0x3a: return "lit10";
+ case 0x3b: return "lit11";
+ case 0x3c: return "lit12";
+ case 0x3d: return "lit13";
+ case 0x3e: return "lit14";
+ case 0x3f: return "lit15";
+ case 0x40: return "lit16";
+ case 0x41: return "lit17";
+ case 0x42: return "lit18";
+ case 0x43: return "lit19";
+ case 0x44: return "lit20";
+ case 0x45: return "lit21";
+ case 0x46: return "lit22";
+ case 0x47: return "lit23";
+ case 0x48: return "lit24";
+ case 0x49: return "lit25";
+ case 0x4a: return "lit26";
+ case 0x4b: return "lit27";
+ case 0x4c: return "lit28";
+ case 0x4d: return "lit29";
+ case 0x4e: return "lit30";
+ case 0x4f: return "lit31";
+ case 0x50: return "reg0";
+ case 0x51: return "reg1";
+ case 0x52: return "reg2";
+ case 0x53: return "reg3";
+ case 0x54: return "reg4";
+ case 0x55: return "reg5";
+ case 0x56: return "reg6";
+ case 0x57: return "reg7";
+ case 0x58: return "reg8";
+ case 0x59: return "reg9";
+ case 0x5a: return "reg10";
+ case 0x5b: return "reg11";
+ case 0x5c: return "reg12";
+ case 0x5d: return "reg13";
+ case 0x5e: return "reg14";
+ case 0x5f: return "reg15";
+ case 0x60: return "reg16";
+ case 0x61: return "reg17";
+ case 0x62: return "reg18";
+ case 0x63: return "reg19";
+ case 0x64: return "reg20";
+ case 0x65: return "reg21";
+ case 0x66: return "reg22";
+ case 0x67: return "reg23";
+ case 0x68: return "reg24";
+ case 0x69: return "reg25";
+ case 0x6a: return "reg26";
+ case 0x6b: return "reg27";
+ case 0x6c: return "reg28";
+ case 0x6d: return "reg29";
+ case 0x6e: return "reg30";
+ case 0x6f: return "reg31";
+ case 0x70: return "breg0";
+ case 0x71: return "breg1";
+ case 0x72: return "breg2";
+ case 0x73: return "breg3";
+ case 0x74: return "breg4";
+ case 0x75: return "breg5";
+ case 0x76: return "breg6";
+ case 0x77: return "breg7";
+ case 0x78: return "breg8";
+ case 0x79: return "breg9";
+ case 0x7a: return "breg10";
+ case 0x7b: return "breg11";
+ case 0x7c: return "breg12";
+ case 0x7d: return "breg13";
+ case 0x7e: return "breg14";
+ case 0x7f: return "breg15";
+ case 0x80: return "breg16";
+ case 0x81: return "breg17";
+ case 0x82: return "breg18";
+ case 0x83: return "breg19";
+ case 0x84: return "breg20";
+ case 0x85: return "breg21";
+ case 0x86: return "breg22";
+ case 0x87: return "breg23";
+ case 0x88: return "breg24";
+ case 0x89: return "breg25";
+ case 0x8a: return "breg26";
+ case 0x8b: return "breg27";
+ case 0x8c: return "breg28";
+ case 0x8d: return "breg29";
+ case 0x8e: return "breg30";
+ case 0x8f: return "breg31";
+ case 0x90: return "regx";
+ case 0x91: return "fbreg";
+ case 0x92: return "bregx";
+ case 0x93: return "piece";
+ case 0x94: return "deref size";
+ case 0x95: return "xderef size";
+ case 0x96: return "nop";
+ case 0x97: return "push object address";
+ case 0x98: return "call2";
+ case 0x99: return "call4";
+ case 0x9a: return "call ref";
+ case 0xf0: return "uninitialized";
+ case 0xe0: return "lo user";
+ case 0xff: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_OP constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+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;
+ }
+}
+
+/* [7.8] Figure 23 "Base type encoding values" (pp. 140-141) in DWARFv3 draft 8 */
+
+const char *
+DW_ATE_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "DW_ATE_address";
+ case 0x02: return "DW_ATE_boolean";
+ case 0x03: return "DW_ATE_complex_float";
+ case 0x04: return "DW_ATE_float";
+ case 0x05: return "DW_ATE_signed";
+ case 0x06: return "DW_ATE_signed_char";
+ case 0x07: return "DW_ATE_unsigned";
+ case 0x08: return "DW_ATE_unsigned_char";
+ case 0x09: return "DW_ATE_imaginary_float";
+ case 0x80: return "DW_ATE_lo_user";
+ case 0xff: return "DW_ATE_hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ATE constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_ATE_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "address";
+ case 0x02: return "boolean";
+ case 0x03: return "complex float";
+ case 0x04: return "float";
+ case 0x05: return "signed";
+ case 0x06: return "signed char";
+ case 0x07: return "unsigned";
+ case 0x08: return "unsigned char";
+ case 0x09: return "imaginary float";
+ case 0x80: return "lo user";
+ case 0xff: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ATE constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_ATE_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x01: return 0;
+ case 0x02: return 0;
+ case 0x03: return 0;
+ case 0x04: return 0;
+ case 0x05: return 0;
+ case 0x06: return 0;
+ case 0x07: return 0;
+ case 0x08: return 0;
+ case 0x09: return DRC_DWARFv3;
+ case 0x80: return 0;
+ case 0xff: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.9] Figure 24 "Accessibility encodings" (p. 141) in DWARFv3 draft 8 */
+
+const char *
+DW_ACCESS_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x1: return "DW_ACCESS_public";
+ case 0x2: return "DW_ACCESS_protected";
+ case 0x3: return "DW_ACCESS_private";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ACCESS constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_ACCESS_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x1: return "public";
+ case 0x2: return "protected";
+ case 0x3: return "private";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ACCESS constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_ACCESS_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x1: return 0;
+ case 0x2: return 0;
+ case 0x3: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.10] Figure 25 "Visibility encodings" (p. 142) in DWARFv3 draft 8 */
+
+const char *
+DW_VIS_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x1: return "DW_VIS_local";
+ case 0x2: return "DW_VIS_exported";
+ case 0x3: return "DW_VIS_qualified";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_VIS constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_VIS_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x1: return "local";
+ case 0x2: return "exported";
+ case 0x3: return "qualified";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_VIS constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_VIS_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x1: return 0;
+ case 0x2: return 0;
+ case 0x3: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.11] Figure 26 "Virtuality encodings" (p. 142) in DWARFv3 draft 8 */
+
+const char *
+DW_VIRTUALITY_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_VIRTUALITY_none";
+ case 0x1: return "DW_VIRTUALITY_virtual";
+ case 0x2: return "DW_VIRTUALITY_pure_virtual";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_VIRTUALITY constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_VIRTUALITY_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "none";
+ case 0x1: return "virtual";
+ case 0x2: return "pure virtual";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_VIRTUALITY constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_VIRTUALITY_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ case 0x1: return 0;
+ case 0x2: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.12] Figure 27 "Language encodings" (p. 143) in DWARFv3 draft 8 */
+
+const char *
+DW_LANG_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0001: return "DW_LANG_C89";
+ case 0x0002: return "DW_LANG_C";
+ case 0x0003: return "DW_LANG_Ada83";
+ case 0x0004: return "DW_LANG_C_plus_plus";
+ case 0x0005: return "DW_LANG_Cobol74";
+ case 0x0006: return "DW_LANG_Cobol85";
+ case 0x0007: return "DW_LANG_Fortran77";
+ case 0x0008: return "DW_LANG_Fortran90";
+ case 0x0009: return "DW_LANG_Pascal83";
+ case 0x000a: return "DW_LANG_Modula2";
+ case 0x000b: return "DW_LANG_Java";
+ case 0x000c: return "DW_LANG_C99";
+ case 0x000d: return "DW_LANG_Ada95";
+ case 0x000e: return "DW_LANG_Fortran95";
+ case 0x000f: return "DW_LANG_PLI";
+ case 0x0010: return "DW_LANG_ObjC";
+ case 0x0011: return "DW_LANG_ObjC_plus_plus";
+ case 0x0012: return "DW_LANG_UPC";
+ case 0x0013: return "DW_LANG_D";
+ case 0x8000: return "DW_LANG_lo_user";
+ case 0x8001: return "DW_LANG_Mips_Assembler";
+ case 0x8765: return "DW_LANG_Upc";
+ case 0xffff: return "DW_LANG_hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_LANG constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_LANG_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0001: return "C89";
+ case 0x0002: return "C";
+ case 0x0003: return "Ada83";
+ case 0x0004: return "C++";
+ case 0x0005: return "Cobol74";
+ case 0x0006: return "Cobol85";
+ case 0x0007: return "Fortran77";
+ case 0x0008: return "Fortran90";
+ case 0x0009: return "Pascal83";
+ case 0x000a: return "Modula2";
+ case 0x000b: return "Java";
+ case 0x000c: return "C99";
+ case 0x000d: return "Ada95";
+ case 0x000e: return "Fortran95";
+ case 0x000f: return "PLI";
+ case 0x0010: return "Objective C";
+ case 0x0011: return "Objective C++";
+ case 0x0012: return "UPC";
+ case 0x0013: return "D";
+ case 0x8000: return "lo user";
+ case 0x8001: return "MIPS Assembler";
+ case 0x8765: return "UPC";
+ case 0xffff: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_LANG constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_LANG_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0001: return 0;
+ case 0x0002: return 0;
+ case 0x0003: return 0;
+ case 0x0004: return 0;
+ case 0x0005: return 0;
+ case 0x0006: return 0;
+ case 0x0007: return 0;
+ case 0x0008: return 0;
+ case 0x0009: return 0;
+ case 0x000a: return 0;
+ case 0x000b: return DRC_DWARFv3;
+ case 0x000c: return DRC_DWARFv3;
+ case 0x000d: return DRC_DWARFv3;
+ case 0x000e: return DRC_DWARFv3;
+ case 0x000f: return DRC_DWARFv3;
+ case 0x0010: return DRC_DWARFv3;
+ case 0x0011: return DRC_DWARFv3;
+ case 0x0012: return DRC_DWARFv3;
+ case 0x0013: return DRC_DWARFv3;
+ case 0x8000: return 0;
+ case 0x8001: return 0;
+ case 0x8765: return 0;
+ case 0xffff: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.13], "Address Class Encodings" (p. 144) in DWARFv3 draft 8 */
+
+const char *
+DW_ADDR_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_ADDR_none";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ADDR constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_ADDR_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "none";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ADDR constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_ADDR_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.14] Figure 28 "Identifier case encodings" (p. 144) in DWARFv3 draft 8 */
+
+const char *
+DW_ID_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_ID_case_sensitive";
+ case 0x1: return "DW_ID_up_case";
+ case 0x2: return "DW_ID_down_case";
+ case 0x3: return "DW_ID_case_insensitive";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ID constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_ID_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "case sensitive";
+ case 0x1: return "up case";
+ case 0x2: return "down case";
+ case 0x3: return "case insensitive";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ID constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_ID_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ case 0x1: return 0;
+ case 0x2: return 0;
+ case 0x3: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.15] Figure 29 "Calling convention encodings" (p. 144) in DWARFv3 draft 8 */
+
+const char *
+DW_CC_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "DW_CC_normal";
+ case 0x02: return "DW_CC_program";
+ case 0x03: return "DW_CC_nocall";
+ case 0x40: return "DW_CC_lo_user";
+ case 0xff: return "DW_CC_hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_CC constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_CC_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "normal";
+ case 0x02: return "program";
+ case 0x03: return "nocall";
+ case 0x40: return "lo user";
+ case 0xff: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_CC constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_CC_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x01: return 0;
+ case 0x02: return 0;
+ case 0x03: return 0;
+ case 0x40: return 0;
+ case 0xff: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.16] Figure 30 "Inline encodings" (p. 145) in DWARFv3 draft 8 */
+
+const char *
+DW_INL_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_INL_not_inlined";
+ case 0x1: return "DW_INL_inlined";
+ case 0x2: return "DW_INL_declared_not_inlined";
+ case 0x3: return "DW_INL_declared_inlined";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_INL constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_INL_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "not inlined";
+ case 0x1: return "inlined";
+ case 0x2: return "declared not inlined";
+ case 0x3: return "declared inlined";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_INL constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_INL_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ case 0x1: return 0;
+ case 0x2: return 0;
+ case 0x3: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.17] Figure 31 "Ordering encodings" (p. 145) in DWARFv3 draft 8 */
+
+const char *
+DW_ORD_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_ORD_row_major";
+ case 0x1: return "DW_ORD_col_major";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ORD constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_ORD_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "row major";
+ case 0x1: return "col major";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_ORD constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_ORD_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ case 0x1: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.18] Figure 32 "Discriminant descriptor encodings" (p. 146) in DWARFv3 draft 8 */
+
+const char *
+DW_DSC_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "DW_DSC_label";
+ case 0x1: return "DW_DSC_range";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_DSC constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_DSC_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x0: return "label";
+ case 0x1: return "range";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_DSC constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_DSC_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x0: return 0;
+ case 0x1: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.21] Figure 33 "Line Number Standard Opcode Encodings" (pp. 148-149) in DWARFv3 draft 8 */
+
+const char *
+DW_LNS_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x1: return "DW_LNS_copy";
+ case 0x2: return "DW_LNS_advance_pc";
+ case 0x3: return "DW_LNS_advance_line";
+ case 0x4: return "DW_LNS_set_file";
+ case 0x5: return "DW_LNS_set_column";
+ case 0x6: return "DW_LNS_negate_stmt";
+ case 0x7: return "DW_LNS_set_basic_block";
+ case 0x8: return "DW_LNS_const_add_pc";
+ case 0x9: return "DW_LNS_fixed_advance_pc";
+ case 0xa: return "DW_LNS_set_prologue_end";
+ case 0xb: return "DW_LNS_set_epilogue_begin";
+ case 0xc: return "DW_LNS_set_isa";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_LNS constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_LNS_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x1: return "copy";
+ case 0x2: return "advance pc";
+ case 0x3: return "advance line";
+ case 0x4: return "set file";
+ case 0x5: return "set column";
+ case 0x6: return "negate stmt";
+ case 0x7: return "set basic block";
+ case 0x8: return "const add pc";
+ case 0x9: return "fixed advance pc";
+ case 0xa: return "set prologue end";
+ case 0xb: return "set epilogue begin";
+ case 0xc: return "set isa";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_LNS constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_LNS_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x1: return 0;
+ case 0x2: return 0;
+ case 0x3: return 0;
+ case 0x4: return 0;
+ case 0x5: return 0;
+ case 0x6: return 0;
+ case 0x7: return 0;
+ case 0x8: return 0;
+ case 0x9: return 0;
+ case 0xa: return DRC_DWARFv3;
+ case 0xb: return DRC_DWARFv3;
+ case 0xc: return DRC_DWARFv3;
+ default: return 0;
+ }
+}
+
+/* [7.21] Figure 34 "Line Number Extended Opcode Encodings" (p. 149) in DWARFv3 draft 8 */
+
+const char *
+DW_LNE_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "DW_LNE_end_sequence";
+ case 0x02: return "DW_LNE_set_address";
+ case 0x03: return "DW_LNE_define_file";
+ case 0x80: return "DW_LNE_lo_user";
+ case 0xff: return "DW_LNE_hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_LNE constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_LNE_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "end sequence";
+ case 0x02: return "set address";
+ case 0x03: return "define file";
+ case 0x80: return "lo user";
+ case 0xff: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_LNE constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_LNE_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x01: return 0;
+ case 0x02: return 0;
+ case 0x03: return 0;
+ case 0x80: return DRC_DWARFv3;
+ case 0xff: return DRC_DWARFv3;
+ default: return 0;
+ }
+}
+
+/* [7.22] Figure 35 "Macinfo Type Encodings" (p. 150) in DWARFv3 draft 8 */
+
+const char *
+DW_MACINFO_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "DW_MACINFO_define";
+ case 0x02: return "DW_MACINFO_undef";
+ case 0x03: return "DW_MACINFO_start_file";
+ case 0x04: return "DW_MACINFO_end_file";
+ case 0xff: return "DW_MACINFO_vendor_ext";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_MACINFO constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_MACINFO_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x01: return "define";
+ case 0x02: return "undef";
+ case 0x03: return "start file";
+ case 0x04: return "end file";
+ case 0xff: return "vendor ext";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_MACINFO constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_MACINFO_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x01: return 0;
+ case 0x02: return 0;
+ case 0x03: return 0;
+ case 0x04: return 0;
+ case 0xff: return 0;
+ default: return 0;
+ }
+}
+
+/* [7.23] Figure 36 "Call frame instruction encodings" (pp. 151-152) in DWARFv3 draft 8 */
+
+const char *
+DW_CFA_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x40: return "DW_CFA_advance_loc";
+ case 0x80: return "DW_CFA_offset";
+ case 0xc0: return "DW_CFA_restore";
+ case 0x00: return "DW_CFA_nop";
+ case 0x01: return "DW_CFA_set_loc";
+ case 0x02: return "DW_CFA_advance_loc1";
+ case 0x03: return "DW_CFA_advance_loc2";
+ case 0x04: return "DW_CFA_advance_loc4";
+ case 0x05: return "DW_CFA_offset_extended";
+ case 0x06: return "DW_CFA_restore_extended";
+ case 0x07: return "DW_CFA_undefined";
+ case 0x08: return "DW_CFA_same_value";
+ case 0x09: return "DW_CFA_register";
+ case 0x0a: return "DW_CFA_remember_state";
+ case 0x0b: return "DW_CFA_restore_state";
+ case 0x0c: return "DW_CFA_def_cfa";
+ case 0x0d: return "DW_CFA_def_cfa_register";
+ case 0x0e: return "DW_CFA_def_cfa_offset";
+ case 0x0f: return "DW_CFA_def_cfa_expression";
+ case 0x10: return "DW_CFA_expression";
+ case 0x11: return "DW_CFA_offset_extended_sf";
+ case 0x12: return "DW_CFA_def_cfa_sf";
+ case 0x13: return "DW_CFA_def_cfa_offset_sf";
+ case 0x1c: return "DW_CFA_lo_user";
+ case 0x3f: return "DW_CFA_hi_user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_CFA constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_CFA_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x40: return "advance loc";
+ case 0x80: return "offset";
+ case 0xc0: return "restore";
+ case 0x00: return "nop";
+ case 0x01: return "set loc";
+ case 0x02: return "advance loc1";
+ case 0x03: return "advance loc2";
+ case 0x04: return "advance loc4";
+ case 0x05: return "offset extended";
+ case 0x06: return "restore extended";
+ case 0x07: return "undefined";
+ case 0x08: return "same value";
+ case 0x09: return "register";
+ case 0x0a: return "remember state";
+ case 0x0b: return "restore state";
+ case 0x0c: return "def cfa";
+ case 0x0d: return "def cfa register";
+ case 0x0e: return "def cfa offset";
+ case 0x0f: return "def cfa expression";
+ case 0x10: return "expression";
+ case 0x11: return "offset extended sf";
+ case 0x12: return "def cfa sf";
+ case 0x13: return "def cfa offset sf";
+ case 0x1c: return "lo user";
+ case 0x3f: return "hi user";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_CFA constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_CFA_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x40: return DRC_ZEROOPERANDS;
+ case 0x80: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_OFFSET;
+ case 0xc0: return DRC_ZEROOPERANDS;
+ case 0x00: return DRC_ZEROOPERANDS;
+ case 0x01: return DRC_ONEOPERAND | DRC_OPERANDONE_ADDRESS;
+ case 0x02: return DRC_ONEOPERAND | DRC_OPERANDONE_1BYTE_DELTA;
+ case 0x03: return DRC_ONEOPERAND | DRC_OPERANDONE_2BYTE_DELTA;
+ case 0x04: return DRC_ONEOPERAND | DRC_OPERANDONE_4BYTE_DELTA;
+ case 0x05: return DRC_OPERANDTWO_ULEB128_OFFSET | DRC_OPERNADONE_ULEB128_REGISTER | DRC_TWOOPERANDS;
+ case 0x06: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_REGISTER;
+ case 0x07: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_REGISTER;
+ case 0x08: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_REGISTER;
+ case 0x09: return DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_ULEB128_REGISTER | DRC_TWOOPERANDS;
+ case 0x0a: return DRC_ZEROOPERANDS;
+ case 0x0b: return DRC_ZEROOPERANDS;
+ case 0x0c: return DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_ULEB128_OFFSET | DRC_TWOOPERANDS;
+ case 0x0d: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_REGISTER;
+ case 0x0e: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_OFFSET;
+ case 0x0f: return DRC_DWARFv3 | DRC_ONEOPERAND | DRC_OPERANDONE_BLOCK;
+ case 0x10: return DRC_DWARFv3 | DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_BLOCK | DRC_TWOOPERANDS;
+ case 0x11: return DRC_DWARFv3 | DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_SLEB128_OFFSET | DRC_TWOOPERANDS;
+ case 0x12: return DRC_DWARFv3 | DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_SLEB128_OFFSET | DRC_TWOOPERANDS;
+ case 0x13: return DRC_DWARFv3 | DRC_ONEOPERAND | DRC_OPERANDONE_SLEB128_OFFSET;
+ case 0x1c: return 0;
+ case 0x3f: return 0;
+ default: return 0;
+ }
+}
+
+/* FSF exception handling Pointer-Encoding constants (CFI augmentation) -- "DW_EH_PE_..." in the FSF sources */
+
+const char *
+DW_GNU_EH_PE_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x00: return "DW_GNU_EH_PE_absptr";
+ case 0x01: return "DW_GNU_EH_PE_uleb128";
+ case 0x02: return "DW_GNU_EH_PE_udata2";
+ case 0x03: return "DW_GNU_EH_PE_udata4";
+ case 0x04: return "DW_GNU_EH_PE_udata8";
+ case 0x09: return "DW_GNU_EH_PE_sleb128";
+ case 0x0a: return "DW_GNU_EH_PE_sdata2";
+ case 0x0b: return "DW_GNU_EH_PE_sdata4";
+ case 0x0c: return "DW_GNU_EH_PE_sdata8";
+ case 0x08: return "DW_GNU_EH_PE_signed";
+ case 0x10: return "DW_GNU_EH_PE_pcrel";
+ case 0x20: return "DW_GNU_EH_PE_textrel";
+ case 0x30: return "DW_GNU_EH_PE_datarel";
+ case 0x40: return "DW_GNU_EH_PE_funcrel";
+ case 0x50: return "DW_GNU_EH_PE_aligned";
+ case 0x80: return "DW_GNU_EH_PE_indirect";
+ case 0xff: return "DW_GNU_EH_PE_omit";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_GNU_EH_PE constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+const char *
+DW_GNU_EH_PE_value_to_englishy_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x00: return "absptr";
+ case 0x01: return "uleb128";
+ case 0x02: return "udata2";
+ case 0x03: return "udata4";
+ case 0x04: return "udata8";
+ case 0x09: return "sleb128";
+ case 0x0a: return "sdata2";
+ case 0x0b: return "sdata4";
+ case 0x0c: return "sdata8";
+ case 0x08: return "signed";
+ case 0x10: return "pcrel";
+ case 0x20: return "textrel";
+ case 0x30: return "datarel";
+ case 0x40: return "funcrel";
+ case 0x50: return "aligned";
+ case 0x80: return "indirect";
+ case 0xff: return "omit";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_GNU_EH_PE constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+DRC_class
+DW_GNU_EH_PE_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x00: return DRC_VENDOR_GNU;
+ case 0x01: return DRC_VENDOR_GNU;
+ case 0x02: return DRC_VENDOR_GNU;
+ case 0x03: return DRC_VENDOR_GNU;
+ case 0x04: return DRC_VENDOR_GNU;
+ case 0x09: return DRC_VENDOR_GNU;
+ case 0x0a: return DRC_VENDOR_GNU;
+ case 0x0b: return DRC_VENDOR_GNU;
+ case 0x0c: return DRC_VENDOR_GNU;
+ case 0x08: return DRC_VENDOR_GNU;
+ case 0x10: return DRC_VENDOR_GNU;
+ case 0x20: return DRC_VENDOR_GNU;
+ case 0x30: return DRC_VENDOR_GNU;
+ case 0x40: return DRC_VENDOR_GNU;
+ case 0x50: return DRC_VENDOR_GNU;
+ case 0x80: return DRC_VENDOR_GNU;
+ case 0xff: return DRC_VENDOR_GNU;
+ default: return 0;
+ }
+}
+
+bool
+is_type_tag (uint16_t tag)
+{
+ switch (tag)
+ {
+ case DW_TAG_array_type:
+ case DW_TAG_base_type:
+ case DW_TAG_class_type:
+ case DW_TAG_const_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_file_type:
+ case DW_TAG_interface_type:
+ case DW_TAG_packed_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_set_type:
+ case DW_TAG_shared_type:
+ case DW_TAG_string_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_subrange_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_thrown_type:
+ case DW_TAG_union_type:
+ case DW_TAG_unspecified_type:
+ case DW_TAG_volatile_type:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool
+is_pubtype_tag (uint16_t tag)
+{
+ switch (tag)
+ {
+ case DW_TAG_array_type:
+ case DW_TAG_class_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_file_type:
+ case DW_TAG_interface_type:
+ case DW_TAG_set_type:
+ case DW_TAG_string_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_subrange_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_thrown_type:
+ case DW_TAG_typedef:
+ case DW_TAG_union_type:
+ case DW_TAG_unspecified_type:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+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;
+}
+
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h
new file mode 100644
index 00000000000..dafe8a7c8b4
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h
@@ -0,0 +1,252 @@
+//===-- 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 liblldb_DWARFDefines_h_
+#define liblldb_DWARFDefines_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "lldb/Core/dwarf.h"
+
+/* DWARF constants generated on Wed Sep 7 16:41:50 2005 */
+
+typedef uint32_t DRC_class; // Holds DRC_* class bitfields
+
+/* [7.5.4] Figure 16 "Tag Encodings" (pp. 125-127) in DWARFv3 draft 8 */
+
+
+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);
+const char *DW_TAG_value_to_englishy_name (uint32_t val);
+DRC_class DW_TAG_value_to_class (uint32_t val);
+DW_TAG_CategoryEnum get_tag_category (uint16_t tag);
+#define DW_TAG_MAX_NAME_LENGTH 31
+
+
+/* [7.5.4] Figure 17 "Child determination encodings" (p. 128) in DWARFv3 draft 8 */
+
+const char *DW_CHILDREN_value_to_name (uint8_t val);
+const char *DW_CHILDREN_value_to_englishy_name (uint8_t val);
+DRC_class DW_CHILDREN_value_to_class (uint32_t val);
+#define DW_CHILDREN_MAX_NAME_LENGTH 15
+
+
+/* [7.5.4] Figure 18 "Attribute encodings" (pp. 129-132) in DWARFv3 draft 8 */
+
+
+const char *DW_AT_value_to_name (uint32_t val);
+const char *DW_AT_value_to_englishy_name (uint32_t val);
+DRC_class DW_AT_value_to_class (uint32_t val);
+#define DW_AT_MAX_NAME_LENGTH 34
+
+
+/* [7.5.4] Figure 19 "Attribute form encodings" (pp. 133-134) in DWARFv3 draft 8 */
+
+const char *DW_FORM_value_to_name (uint32_t val);
+const char *DW_FORM_value_to_englishy_name (uint32_t val);
+DRC_class DW_FORM_value_to_class (uint32_t val);
+#define DW_FORM_MAX_NAME_LENGTH 17
+
+
+/* [7.7.1] Figure 22 "DWARF operation encodings" (pp. 136-139) in DWARFv3 draft 8 */
+
+const char *DW_OP_value_to_name (uint32_t val);
+const char *DW_OP_value_to_englishy_name (uint32_t val);
+DRC_class DW_OP_value_to_class (uint32_t val);
+#define DW_OP_MAX_NAME_LENGTH 25
+
+
+/* [7.8] Figure 23 "Base type encoding values" (pp. 140-141) in DWARFv3 draft 8 */
+
+const char *DW_ATE_value_to_name (uint32_t val);
+const char *DW_ATE_value_to_englishy_name (uint32_t val);
+DRC_class DW_ATE_value_to_class (uint32_t val);
+#define DW_ATE_MAX_NAME_LENGTH 22
+
+
+/* [7.9] Figure 24 "Accessibility encodings" (p. 141) in DWARFv3 draft 8 */
+
+const char *DW_ACCESS_value_to_name (uint32_t val);
+const char *DW_ACCESS_value_to_englishy_name (uint32_t val);
+DRC_class DW_ACCESS_value_to_class (uint32_t val);
+#define DW_ACCESS_MAX_NAME_LENGTH 19
+
+
+/* [7.10] Figure 25 "Visibility encodings" (p. 142) in DWARFv3 draft 8 */
+
+const char *DW_VIS_value_to_name (uint32_t val);
+const char *DW_VIS_value_to_englishy_name (uint32_t val);
+DRC_class DW_VIS_value_to_class (uint32_t val);
+#define DW_VIS_MAX_NAME_LENGTH 16
+
+
+/* [7.11] Figure 26 "Virtuality encodings" (p. 142) in DWARFv3 draft 8 */
+
+const char *DW_VIRTUALITY_value_to_name (uint32_t val);
+const char *DW_VIRTUALITY_value_to_englishy_name (uint32_t val);
+DRC_class DW_VIRTUALITY_value_to_class (uint32_t val);
+#define DW_VIRTUALITY_MAX_NAME_LENGTH 26
+
+
+/* [7.12] Figure 27 "Language encodings" (p. 143) in DWARFv3 draft 8 */
+
+const char *DW_LANG_value_to_name (uint32_t val);
+const char *DW_LANG_value_to_englishy_name (uint32_t val);
+DRC_class DW_LANG_value_to_class (uint32_t val);
+#define DW_LANG_MAX_NAME_LENGTH 19
+
+
+/* [7.13], "Address Class Encodings" (p. 144) in DWARFv3 draft 8 */
+
+const char *DW_ADDR_value_to_name (uint32_t val);
+const char *DW_ADDR_value_to_englishy_name (uint32_t val);
+DRC_class DW_ADDR_value_to_class (uint32_t val);
+#define DW_ADDR_MAX_NAME_LENGTH 12
+
+
+/* [7.14] Figure 28 "Identifier case encodings" (p. 144) in DWARFv3 draft 8 */
+
+const char *DW_ID_value_to_name (uint32_t val);
+const char *DW_ID_value_to_englishy_name (uint32_t val);
+DRC_class DW_ID_value_to_class (uint32_t val);
+#define DW_ID_MAX_NAME_LENGTH 22
+
+
+/* [7.15] Figure 29 "Calling convention encodings" (p. 144) in DWARFv3 draft 8 */
+
+const char *DW_CC_value_to_name (uint32_t val);
+const char *DW_CC_value_to_englishy_name (uint32_t val);
+DRC_class DW_CC_value_to_class (uint32_t val);
+#define DW_CC_MAX_NAME_LENGTH 13
+
+
+/* [7.16] Figure 30 "Inline encodings" (p. 145) in DWARFv3 draft 8 */
+
+const char *DW_INL_value_to_name (uint32_t val);
+const char *DW_INL_value_to_englishy_name (uint32_t val);
+DRC_class DW_INL_value_to_class (uint32_t val);
+#define DW_INL_MAX_NAME_LENGTH 27
+
+
+/* [7.17] Figure 31 "Ordering encodings" (p. 145) in DWARFv3 draft 8 */
+
+const char *DW_ORD_value_to_name (uint32_t val);
+const char *DW_ORD_value_to_englishy_name (uint32_t val);
+DRC_class DW_ORD_value_to_class (uint32_t val);
+#define DW_ORD_MAX_NAME_LENGTH 16
+
+
+/* [7.18] Figure 32 "Discriminant descriptor encodings" (p. 146) in DWARFv3 draft 8 */
+
+const char *DW_DSC_value_to_name (uint32_t val);
+const char *DW_DSC_value_to_englishy_name (uint32_t val);
+DRC_class DW_DSC_value_to_class (uint32_t val);
+#define DW_DSC_MAX_NAME_LENGTH 12
+
+
+/* [7.21] Figure 33 "Line Number Standard Opcode Encodings" (pp. 148-149) in DWARFv3 draft 8 */
+
+const char *DW_LNS_value_to_name (uint32_t val);
+const char *DW_LNS_value_to_englishy_name (uint32_t val);
+DRC_class DW_LNS_value_to_class (uint32_t val);
+#define DW_LNS_MAX_NAME_LENGTH 25
+
+
+/* [7.21] Figure 34 "Line Number Extended Opcode Encodings" (p. 149) in DWARFv3 draft 8 */
+
+const char *DW_LNE_value_to_name (uint32_t val);
+const char *DW_LNE_value_to_englishy_name (uint32_t val);
+DRC_class DW_LNE_value_to_class (uint32_t val);
+#define DW_LNE_MAX_NAME_LENGTH 19
+
+
+/* [7.22] Figure 35 "Macinfo Type Encodings" (p. 150) in DWARFv3 draft 8 */
+
+const char *DW_MACINFO_value_to_name (uint32_t val);
+const char *DW_MACINFO_value_to_englishy_name (uint32_t val);
+DRC_class DW_MACINFO_value_to_class (uint32_t val);
+#define DW_MACINFO_MAX_NAME_LENGTH 21
+
+
+/* [7.23] Figure 36 "Call frame instruction encodings" (pp. 151-152) in DWARFv3 draft 8 */
+
+const char *DW_CFA_value_to_name (uint32_t val);
+const char *DW_CFA_value_to_englishy_name (uint32_t val);
+DRC_class DW_CFA_value_to_class (uint32_t val);
+#define DW_CFA_MAX_NAME_LENGTH 25
+
+
+/* FSF exception handling Pointer-Encoding constants (CFI augmentation) -- "DW_EH_PE_..." in the FSF sources */
+
+const char *DW_GNU_EH_PE_value_to_name (uint32_t val);
+const char *DW_GNU_EH_PE_value_to_englishy_name (uint32_t val);
+DRC_class DW_GNU_EH_PE_value_to_class (uint32_t val);
+#define DW_GNU_EH_PE_MAX_NAME_LENGTH 21
+
+
+/* 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
+
+bool is_type_tag (uint16_t tag);
+bool is_pubtype_tag (uint16_t tag);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // liblldb_DWARFDefines_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
new file mode 100644
index 00000000000..d2c137bd7df
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
@@ -0,0 +1,571 @@
+//===-- 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;
+
+DWARFFormValue::DWARFFormValue(dw_form_t form) :
+ m_form(form),
+ m_value()
+{
+}
+
+bool
+DWARFFormValue::ExtractValue(const DataExtractor& data, uint32_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_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: m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu)); 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;
+
+ 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, uint32_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, uint32_t* offset_ptr, const DWARFCompileUnit* cu)
+{
+ bool indirect = false;
+ do
+ {
+ indirect = false;
+ switch (form)
+ {
+ // Blocks if inlined data that have a length field and the data bytes
+ // inlined in the .debug_info
+ 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 :
+ case DW_FORM_ref_addr :
+ *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu);
+ 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;
+
+ // 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 :
+ *offset_ptr += 8;
+ return true;
+
+ // signed or unsigned LEB 128 values
+ // case DW_FORM_APPLE_db_str:
+ 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 :
+ indirect = true;
+ form = debug_info_data.GetULEB128(offset_ptr);
+ break;
+ default:
+ return false;
+ }
+ } while (indirect);
+ return true;
+}
+
+//bool
+//DWARFFormValue::PutUnsigned(dw_form_t form, dw_offset_t offset, uint64_t value, BinaryStreamBuf& out_buff, const DWARFCompileUnit* cu, bool fixup_cu_relative_refs)
+//{
+// assert(offset != DW_INVALID_OFFSET);
+//// printf("PutUnsigned(%s, 0x%8.8x, 0x%16.16llx, %d)\n", DW_FORM_value_to_name(form), offset, value, fixup_cu_relative_refs);
+// // Read the value for the form into value and follow and DW_FORM_indirect instances we run into
+// switch (form)
+// {
+// case DW_FORM_addr: offset = out_buff.PutMax64(offset, value, DWARFCompileUnit::GetAddressByteSize(cu)); break;
+//
+// case DW_FORM_flag:
+// case DW_FORM_data1: offset = out_buff.Put8(offset, value); break;
+// case DW_FORM_data2: offset = out_buff.Put16(offset, value); break;
+// case DW_FORM_data4: offset = out_buff.Put32(offset, value); break;
+// case DW_FORM_data8: offset = out_buff.Put64(offset, value); break;
+//// case DW_FORM_udata: offset = out_buff.Put32_as_ULEB128(offset, value); break;
+//// case DW_FORM_sdata: offset = out_buff.Put32_as_SLEB128(offset, value); break;
+// case DW_FORM_strp: offset = out_buff.Put32(offset, value); break;
+//// case DW_FORM_APPLE_db_str:
+//// offset = out_buff.Put32_as_ULEB128(offset, value); break;
+//
+// case DW_FORM_ref1:
+// if (fixup_cu_relative_refs) value -= cu->GetOffset();
+// offset = out_buff.Put8(offset, value);
+// break;
+// case DW_FORM_ref2:
+// if (fixup_cu_relative_refs) value -= cu->GetOffset();
+// offset = out_buff.Put16(offset, value);
+// break;
+// case DW_FORM_ref4:
+// if (fixup_cu_relative_refs) value -= cu->GetOffset();
+// offset = out_buff.Put32(offset, value);
+// break;
+// case DW_FORM_ref8:
+// if (fixup_cu_relative_refs) value -= cu->GetOffset();
+// offset = out_buff.Put64(offset, value);
+// break;
+//// case DW_FORM_ref_udata:
+//// if (fixup_cu_relative_refs) value -= cu->GetOffset();
+//// offset = out_buff.Put32_as_ULEB128(offset, value);
+//// break;
+// case DW_FORM_ref_addr:
+// // TODO: Add support for DWARF3 if we ever start emitting DWARF3. The DW_FORM_ref_addr
+// // is always the same size as an address prior to DWARF3, and with DWARF3 or later it
+// // is 4 hard coded to bytes.
+// offset = out_buff.PutMax64(offset, value, DWARFCompileUnit::GetAddressByteSize(cu));
+// break;
+//
+// default:
+// return false;
+// }
+//
+// return true;
+//}
+
+//bool
+//DWARFFormValue::TransferValue(dw_form_t form, const DataExtractor& data, uint32_t* offset_ptr, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff)
+//{
+// DWARFFormValue formValue(form);
+// if (formValue.ExtractValue(data, offset_ptr,cu))
+// return TransferValue(formValue, cu, out_buff);
+// return false;
+//}
+
+//bool
+//DWARFFormValue::TransferValue(const DWARFFormValue& formValue, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff)
+//{
+// // Read the value for the form into value and follow and DW_FORM_indirect instances we run into
+// dw_form_t form = formValue.Form();
+// switch (form)
+// {
+// case DW_FORM_addr:
+// case DW_FORM_ref_addr:
+// {
+// uint8_t addr_size = DWARFCompileUnit::GetAddressByteSize(cu);
+// out_buff.AppendMax64(formValue.Unsigned(), addr_size);
+// }
+// break;
+//
+// case DW_FORM_block: out_buff.Append32_as_ULEB128(formValue.Unsigned()); break;
+// case DW_FORM_block1: out_buff.Append8(formValue.Unsigned()); break;
+// case DW_FORM_block2: out_buff.Append16(formValue.Unsigned()); break;
+// case DW_FORM_block4: out_buff.Append32(formValue.Unsigned()); break;
+//
+// case DW_FORM_flag:
+// case DW_FORM_data1: out_buff.Append8(formValue.Unsigned()); break;
+// case DW_FORM_data2: out_buff.Append16(formValue.Unsigned()); break;
+// case DW_FORM_data4: out_buff.Append32(formValue.Unsigned()); break;
+// case DW_FORM_data8: out_buff.Append64(formValue.Unsigned()); break;
+// case DW_FORM_udata: out_buff.Append32_as_ULEB128(formValue.Unsigned()); break;
+// case DW_FORM_sdata: out_buff.Append32_as_SLEB128(formValue.Signed()); break;
+//
+// case DW_FORM_string: out_buff.AppendCStr(formValue.m_value.value.cstr); break;
+// case DW_FORM_strp: out_buff.Append32(formValue.Unsigned()); break;
+//// case DW_FORM_APPLE_db_str:
+//// out_buff.Append32_as_ULEB128(formValue.Unsigned()); break;
+//
+// case DW_FORM_ref1: out_buff.Append8(formValue.Unsigned()); break;
+// case DW_FORM_ref2: out_buff.Append16(formValue.Unsigned()); break;
+// case DW_FORM_ref4: out_buff.Append32(formValue.Unsigned()); break;
+// case DW_FORM_ref8: out_buff.Append64(formValue.Unsigned()); break;
+// case DW_FORM_ref_udata: out_buff.Append32_as_ULEB128(formValue.Unsigned()); break;
+//
+// case DW_FORM_indirect:
+// assert(!"DW_FORM_indirect found in DWARFFormValue::TransferValue() for an extracted form...");
+// break;
+//
+// default:
+// Log::Error("DWARFFormValue::TransferValue() Unrecognized form: 0x%4.4x", form);
+// return false;
+// break;
+// }
+//
+// const uint8_t* block_data = formValue.BlockData();
+// if (block_data)
+// out_buff.AppendData(block_data, formValue.Unsigned());
+// return true;
+//}
+
+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_data4: s->PutHex32(uvalue); break;
+ case DW_FORM_data8: s->PutHex64(uvalue); break;
+ case DW_FORM_string: s->QuotedCString(AsCString(NULL)); break;
+ 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_block: s->Printf("<0x%llx> ", 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:
+ {
+ s->Address(uvalue, sizeof (uint64_t) * 2);
+ 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.8llx", uvalue); break;
+ case DW_FORM_ref_udata: cu_relative_offset = true; if (verbose) s->Printf("cu + 0x%llx", 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;
+ default:
+ s->Printf("DW_FORM(0x%4.4x)", m_form);
+ break;
+ }
+
+ if (cu_relative_offset)
+ {
+ if (verbose)
+ s->PutCString(" => ");
+
+ s->Printf("{0x%8.8x}", (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;
+}
+
+//----------------------------------------------------------------------
+// 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:
+ {
+ 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:
+ {
+ 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/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
new file mode 100644
index 00000000000..3db63664f38
--- /dev/null
+++ b/lldb/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 liblldb_DWARFFormValue_h_
+ #define SymbolFileDWARF_DWARFFormValue_h_
+
+#include "SymbolFileDWARF.h"
+#include <stddef.h> // for NULL
+
+class DWARFFormValue
+{
+public:
+ typedef struct ValueTypeTag
+ {
+ ValueTypeTag() :
+ data(NULL),
+ value()
+ {
+ 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, uint32_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;
+ bool ResolveCompileUnitReferences(const DWARFCompileUnit* cu);
+ 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, uint32_t* offset_ptr, const DWARFCompileUnit* cu) const;
+ static bool SkipValue(const dw_form_t form, const lldb_private::DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu);
+// static bool TransferValue(dw_form_t form, const lldb_private::DataExtractor& debug_info_data, uint32_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 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/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp
new file mode 100644
index 00000000000..9229c2a2d22
--- /dev/null
+++ b/lldb/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, uint32_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;
+ uint32_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,
+ uint32_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_englishy_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("%llu %lli", 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("%+lli", sint); break;
+ case -2: sint = (int16_t) data.GetU16(offset_ptr); s->Printf("%+lli", sint); break;
+ case -4: sint = (int32_t) data.GetU32(offset_ptr); s->Printf("%+lli", sint); break;
+ case -8: sint = (int64_t) data.GetU64(offset_ptr); s->Printf("%+lli", sint); break;
+ case -128: sint = data.GetSLEB128(offset_ptr); s->Printf("%+lli", sint); break;
+ case 1: uint = data.GetU8(offset_ptr); s->Printf("0x%2.2llx", uint); break;
+ case 2: uint = data.GetU16(offset_ptr); s->Printf("0x%4.4llx", uint); break;
+ case 4: uint = data.GetU32(offset_ptr); s->Printf("0x%8.8llx", uint); break;
+ case 8: uint = data.GetU64(offset_ptr); s->Printf("0x%16.16llx", uint); break;
+ case 128: uint = data.GetULEB128(offset_ptr); s->Printf("0x%llx", uint); break;
+ }
+
+ return 0;
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h
new file mode 100644
index 00000000000..413a95c0f49
--- /dev/null
+++ b/lldb/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 liblldb_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/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp
new file mode 100644
index 00000000000..6a8359d3986
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp
@@ -0,0 +1,89 @@
+//===-- 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, dw_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();
+ s->AddressRange(start_addr + base_addr, end_addr + base_addr, 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, dw_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, dw_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/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h
new file mode 100644
index 00000000000..3efd5c4492b
--- /dev/null
+++ b/lldb/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 liblldb_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,
+ dw_offset_t offset);
+
+ static bool
+ Extract (const lldb_private::DataExtractor& debug_loc_data,
+ dw_offset_t* offset_ptr,
+ lldb_private::DataExtractor& location_list_data);
+
+ static size_t
+ Size (const lldb_private::DataExtractor& debug_loc_data,
+ dw_offset_t offset);
+
+};
+#endif // SymbolFileDWARF_DWARFLocationList_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
new file mode 100644
index 00000000000..571271b34bb
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
@@ -0,0 +1,207 @@
+//===-- 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/Core/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 ();
+}
+
+const char *
+LogChannelDWARF::GetPluginNameStatic()
+{
+ static std::string g_plugin_name;
+ if (g_plugin_name.empty())
+ {
+ g_plugin_name = SymbolFileDWARF::GetPluginNameStatic();
+ g_plugin_name += LogChannel::GetPluginSuffix ();
+ }
+ return g_plugin_name.c_str();
+}
+
+
+const char *
+LogChannelDWARF::GetPluginDescriptionStatic()
+{
+ return "DWARF log channel for debugging plug-in issues.";
+}
+
+const char *
+LogChannelDWARF::GetPluginName()
+{
+ return GetPluginDescriptionStatic();
+}
+
+const char *
+LogChannelDWARF::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+LogChannelDWARF::GetPluginVersion()
+{
+ return 1;
+}
+
+
+void
+LogChannelDWARF::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+
+Error
+LogChannelDWARF::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorStringWithFormat("No commands are supported.\n");
+ return error;
+}
+
+
+Log *
+LogChannelDWARF::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
+void
+LogChannelDWARF::Disable ()
+{
+ g_log_channel = NULL;
+ m_log_sp.reset();
+}
+
+bool
+LogChannelDWARF::Enable
+(
+ StreamSP &log_stream_sp,
+ uint32_t log_options,
+ Stream *feedback_strm, // Feedback stream for argument errors etc
+ const Args &categories // The categories to enable within this logging stream, if empty, enable default set
+)
+{
+ Disable ();
+
+ m_log_sp.reset(new Log (log_stream_sp));
+ g_log_channel = this;
+ uint32_t flag_bits = 0;
+ bool got_unknown_category = false;
+ const size_t argc = categories.GetArgumentCount();
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *arg = categories.GetArgumentAtIndex(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, "default") == 0 ) flag_bits |= DWARF_LOG_DEFAULT;
+ 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_sp->GetMask().SetAllFlagBits(flag_bits);
+ m_log_sp->GetOptions().SetAllFlagBits(log_options);
+ return m_log_sp.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\n",
+ SymbolFileDWARF::GetPluginNameStatic());
+}
+
+Log *
+LogChannelDWARF::GetLog ()
+{
+ if (g_log_channel)
+ return g_log_channel->m_log_sp.get();
+ else
+ return NULL;
+}
+
+Log *
+LogChannelDWARF::GetLogIfAll (uint32_t mask)
+{
+ Log *log = GetLog();
+ if (log)
+ if (log->GetMask().IsSet(mask))
+ return log;
+ return NULL;
+}
+
+
+void
+LogChannelDWARF::LogIf (uint32_t mask, const char *format, ...)
+{
+ if (g_log_channel)
+ {
+ LogSP log_sp(g_log_channel->m_log_sp);
+ va_list args;
+ va_start (args, format);
+ log_sp->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
new file mode 100644
index 00000000000..943d1da194f
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
@@ -0,0 +1,91 @@
+//===-- 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 liblldb_LogChannelDWARF_h_
+#define liblldb_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_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 const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::LogChannel *
+ CreateInstance ();
+
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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);
+
+ virtual void
+ Disable ();
+
+ virtual bool
+ Enable (lldb::StreamSP &log_stream_sp,
+ uint32_t log_options,
+ lldb_private::Stream *feedback_strm, // Feedback stream for argument errors etc
+ const lldb_private::Args &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 void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // liblldb_LogChannelDWARF_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
new file mode 100644
index 00000000000..ffee695d3ab
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -0,0 +1,3615 @@
+//===-- 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/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 "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/Timer.h"
+#include "lldb/Core/Value.h"
+
+#include "lldb/Symbol/Block.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 "DWARFCompileUnit.h"
+#include "DWARFDebugAbbrev.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDebugInfoEntry.h"
+#include "DWARFDebugLine.h"
+#include "DWARFDebugPubnames.h"
+#include "DWARFDebugRanges.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "DWARFLocationList.h"
+#include "LogChannelDWARF.h"
+
+#include <map>
+
+#define DIE_IS_BEING_PARSED ((void*)1)
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static const ConstString&
+GetSectionNameDebugInfo()
+{
+ static const ConstString g_sect_name("__debug_info");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugAbbrev()
+{
+ static const ConstString g_sect_name ("__debug_abbrev");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugAranges()
+{
+ static const ConstString g_sect_name ("__debug_aranges");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugFrame()
+{
+ static const ConstString g_sect_name ("__debug_frame");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugLine()
+{
+ static const ConstString g_sect_name ("__debug_line");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugLoc()
+{
+ static const ConstString g_sect_name ("__debug_loc");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugMacInfo()
+{
+ static const ConstString g_sect_name ("__debug_macinfo");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugPubNames()
+{
+ static const ConstString g_sect_name ("__debug_pubnames");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugPubTypes()
+{
+ static const ConstString g_sect_name ("__debug_pubtypes");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugRanges()
+{
+ static const ConstString g_sect_name ("__debug_ranges");
+ return g_sect_name;
+}
+
+static const ConstString&
+GetSectionNameDebugStr()
+{
+ static const ConstString g_sect_name ("__debug_str");
+ return g_sect_name;
+}
+
+static uint32_t
+DwarfToClangAccessibility (uint32_t dwarf_accessibility)
+{
+ switch (dwarf_accessibility)
+ {
+ case DW_ACCESS_public:
+ return clang::AS_public;
+ case DW_ACCESS_private:
+ return clang::AS_private;
+ case DW_ACCESS_protected:
+ return clang::AS_protected;
+ default:
+ return clang::AS_none;
+ }
+}
+
+void
+SymbolFileDWARF::Initialize()
+{
+ LogChannelDWARF::Initialize();
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolFileDWARF::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+ LogChannelDWARF::Initialize();
+}
+
+
+const char *
+SymbolFileDWARF::GetPluginNameStatic()
+{
+ return "symbol-file.dwarf2";
+}
+
+const char *
+SymbolFileDWARF::GetPluginDescriptionStatic()
+{
+ return "DWARF and DWARF3 debug symbol file reader.";
+}
+
+
+SymbolFile*
+SymbolFileDWARF::CreateInstance (ObjectFile* obj_file)
+{
+ return new SymbolFileDWARF(obj_file);
+}
+
+//----------------------------------------------------------------------
+// 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* ofile) :
+ SymbolFile(ofile),
+ 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_macinfo(),
+ m_data_debug_pubnames(),
+ m_data_debug_pubtypes(),
+ m_data_debug_ranges(),
+ m_data_debug_str(),
+ m_abbr(),
+ m_aranges(),
+ m_info(),
+ m_line(),
+ m_name_to_function_die(),
+ m_name_to_inlined_die(),
+ m_name_to_global_die(),
+ m_name_to_type_die(),
+ m_indexed(false),
+// m_pubnames(),
+// m_pubtypes(),
+// m_pubbasetypes(),
+ m_ranges()//,
+// m_type_fixups(),
+// m_indirect_fixups()
+{
+}
+
+SymbolFileDWARF::~SymbolFileDWARF()
+{
+}
+
+bool
+SymbolFileDWARF::SupportedVersion(uint16_t version)
+{
+ return version == 2 || version == 3;
+}
+
+uint32_t
+SymbolFileDWARF::GetAbilities ()
+{
+ 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_aranges_file_size = 0;
+ uint64_t debug_frame_file_size = 0;
+ uint64_t debug_info_file_size = 0;
+ uint64_t debug_line_file_size = 0;
+ uint64_t debug_loc_file_size = 0;
+ uint64_t debug_macinfo_file_size = 0;
+ uint64_t debug_pubnames_file_size = 0;
+ uint64_t debug_pubtypes_file_size = 0;
+ uint64_t debug_ranges_file_size = 0;
+ uint64_t debug_str_file_size = 0;
+
+ static ConstString g_dwarf_section_name ("__DWARF");
+
+ section = section_list->FindSectionByName(g_dwarf_section_name).get();
+
+ if (section)
+ section->MemoryMapSectionDataFromObjectFile(m_obj_file, m_dwarf_data);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugInfo()).get();
+ if (section != NULL)
+ {
+ debug_info_file_size = section->GetByteSize();
+
+ section = section_list->FindSectionByName (GetSectionNameDebugAbbrev()).get();
+ if (section)
+ debug_abbrev_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugAbbrevData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugAranges()).get();
+ if (section)
+ debug_aranges_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugArangesData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugFrame()).get();
+ if (section)
+ debug_frame_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugFrameData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugLine()).get();
+ if (section)
+ debug_line_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugLineData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugLoc()).get();
+ if (section)
+ debug_loc_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugLocData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugMacInfo()).get();
+ if (section)
+ debug_macinfo_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugMacInfoData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugPubNames()).get();
+ if (section)
+ debug_pubnames_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugPubNamesData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugPubTypes()).get();
+ if (section)
+ debug_pubtypes_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugPubTypesData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugRanges()).get();
+ if (section)
+ debug_ranges_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugRangesData);
+
+ section = section_list->FindSectionByName (GetSectionNameDebugStr()).get();
+ if (section)
+ debug_str_file_size = section->GetByteSize();
+ else
+ m_flags.Set (flagsGotDebugStrData);
+ }
+
+ 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;
+
+ if (debug_aranges_file_size > 0)
+ abilities |= AddressAcceleratorTable;
+
+ if (debug_pubnames_file_size > 0)
+ abilities |= FunctionAcceleratorTable;
+
+ if (debug_pubtypes_file_size > 0)
+ abilities |= TypeAcceleratorTable;
+
+ if (debug_macinfo_file_size > 0)
+ abilities |= MacroInformation;
+
+ if (debug_frame_file_size > 0)
+ abilities |= CallFrameInformation;
+ }
+ return abilities;
+}
+
+const DataExtractor&
+SymbolFileDWARF::GetCachedSectionData (uint32_t got_flag, const ConstString &section_name, DataExtractor &data)
+{
+ if (m_flags.IsClear (got_flag))
+ {
+ m_flags.Set (got_flag);
+ const SectionList *section_list = m_obj_file->GetSectionList();
+ if (section_list)
+ {
+ Section *section = section_list->FindSectionByName (section_name).get();
+ if (section )
+ {
+ // See if we memory mapped the DWARF segment?
+ if (m_dwarf_data.GetByteSize())
+ {
+ data.SetData(m_dwarf_data, section->GetOffset (), section->GetByteSize());
+ }
+ else
+ {
+ if (section->ReadSectionDataFromObjectFile(m_obj_file, data) == 0)
+ data.Clear();
+ }
+ }
+ }
+ }
+ return data;
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_abbrev_data()
+{
+ return GetCachedSectionData (flagsGotDebugAbbrevData, GetSectionNameDebugAbbrev(), m_data_debug_abbrev);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_aranges_data()
+{
+ return GetCachedSectionData (flagsGotDebugArangesData, GetSectionNameDebugAranges(), m_data_debug_aranges);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_frame_data()
+{
+ return GetCachedSectionData (flagsGotDebugFrameData, GetSectionNameDebugFrame(), m_data_debug_frame);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_info_data()
+{
+ return GetCachedSectionData (flagsGotDebugInfoData, GetSectionNameDebugInfo(), m_data_debug_info);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_line_data()
+{
+ return GetCachedSectionData (flagsGotDebugLineData, GetSectionNameDebugLine(), m_data_debug_line);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_loc_data()
+{
+ return GetCachedSectionData (flagsGotDebugLocData, GetSectionNameDebugLoc(), m_data_debug_loc);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_macinfo_data()
+{
+ return GetCachedSectionData (flagsGotDebugMacInfoData, GetSectionNameDebugMacInfo(), m_data_debug_macinfo);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_pubnames_data()
+{
+ return GetCachedSectionData (flagsGotDebugPubNamesData, GetSectionNameDebugPubNames(), m_data_debug_pubnames);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_pubtypes_data()
+{
+ return GetCachedSectionData (flagsGotDebugPubTypesData, GetSectionNameDebugPubTypes(), m_data_debug_pubtypes);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_ranges_data()
+{
+ return GetCachedSectionData (flagsGotDebugRangesData, GetSectionNameDebugRanges(), m_data_debug_ranges);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_str_data()
+{
+ return GetCachedSectionData (flagsGotDebugStrData, GetSectionNameDebugStr(), m_data_debug_str);
+}
+
+
+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();
+}
+
+DWARFDebugAranges*
+SymbolFileDWARF::DebugAranges()
+{
+ if (m_aranges.get() == NULL)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+ m_aranges.reset(new DWARFDebugAranges());
+ if (m_aranges.get())
+ {
+ const DataExtractor &debug_aranges_data = get_debug_aranges_data();
+ if (debug_aranges_data.GetByteSize() > 0)
+ m_aranges->Extract(debug_aranges_data);
+ else
+ m_aranges->Generate(this);
+ }
+ }
+ return m_aranges.get();
+}
+
+const DWARFDebugAranges*
+SymbolFileDWARF::DebugAranges() const
+{
+ return m_aranges.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();
+}
+
+//DWARFDebugLine*
+//SymbolFileDWARF::DebugLine()
+//{
+// if (m_line.get() == NULL)
+// {
+// Timer scoped_timer(__PRETTY_FUNCTION__);
+// const DataExtractor &debug_line_data = debug_line();
+// if (debug_line_data.GetByteSize() > 0)
+// {
+// m_line.reset(new DWARFDebugLine());
+// if (m_line.get())
+// m_line->Parse(debug_line_data);
+// }
+// }
+// return m_line.get();
+//}
+//
+//const DWARFDebugLine*
+//SymbolFileDWARF::DebugLine() const
+//{
+// return m_line.get();
+//}
+
+
+DWARFCompileUnit*
+SymbolFileDWARF::GetDWARFCompileUnitForUID(lldb::user_id_t cu_uid)
+{
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ return info->GetCompileUnit(cu_uid).get();
+ return NULL;
+}
+
+//DWARFCompileUnit*
+//SymbolFileDWARF::GetNextUnparsedDWARFCompileUnit(DWARFCompileUnit* prev_cu)
+//{
+// DWARFCompileUnit* cu = NULL;
+// DWARFDebugInfo* info = DebugInfo();
+// if (info)
+// {
+// uint32_t cu_idx = 0;
+// if (prev_cu != NULL)
+// {
+// // Find the index of the previus DWARF compile unit if one was provided
+// while ((cu = info->GetCompileUnitAtIndex(cu_idx)) != NULL)
+// {
+// ++cu_idx;
+// if (cu == prev_cu)
+// break;
+// }
+// }
+//
+// // Now find the next unparsed DWARF compile unit. We do this by checking the
+// // user data in the DWARFCompileUnit class that starts as NULL, and eventually
+// // holds a pointer to the CompileUnit that was created for it after it has
+// // been parsed.
+// while ((cu = info->GetCompileUnitAtIndex(cu_idx)) != NULL)
+// {
+// if (cu->GetUserData() == NULL)
+// break;
+// }
+// }
+// return cu;
+//}
+
+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();
+}
+//
+//DWARFDebugPubnames*
+//SymbolFileDWARF::DebugPubnames()
+//{
+// if (m_pubnames.get() == NULL)
+// {
+// Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+// const DataExtractor &debug_pubnames_data = get_debug_pubnames_data();
+// if (debug_pubnames_data.GetByteSize() > 0)
+// {
+// // Pass false to indicate this is a pubnames section
+// m_pubnames.reset(new DWARFDebugPubnames());
+// if (m_pubnames.get())
+// {
+// // "m_pubnames->GeneratePubnames" is costly, but needed for global variables
+// m_pubnames->GeneratePubnames(this);
+//
+//#if 0
+// StreamFile s(stdout);
+// s.Printf (".debug_pubnames for %s/%s:\n",
+// m_obj_file->GetModule()->GetFileSpec().GetDirectory().AsCString(),
+// m_obj_file->GetModule()->GetFileSpec().GetFilename().AsCString());
+// m_pubnames->Dump (&s);
+//#endif
+// // "m_pubnames->Extract" is quicker, but the pubnames don't always contain what we need.
+// //m_pubnames->Extract(debug_pubnames_data);
+// }
+// }
+// }
+// return m_pubnames.get();
+//}
+//
+//const DWARFDebugPubnames*
+//SymbolFileDWARF::DebugPubnames() const
+//{
+// return m_pubnames.get();
+//}
+
+//DWARFDebugPubnames*
+//SymbolFileDWARF::DebugPubBaseTypes()
+//{
+// if (m_pubbasetypes.get() == NULL)
+// {
+// Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+// // Pass false to indicate this is a pubnames section
+// m_pubbasetypes.reset(new DWARFDebugPubnames());
+// if (m_pubbasetypes.get())
+// m_pubbasetypes->GeneratePubBaseTypes(this);
+// }
+// return m_pubbasetypes.get();
+//}
+//
+//const DWARFDebugPubnames*
+//SymbolFileDWARF::DebugPubBaseTypes() const
+//{
+// return m_pubbasetypes.get();
+//}
+//
+//const DWARFDebugPubnames*
+//SymbolFileDWARF::DebugPubtypes() const
+//{
+// return m_pubtypes.get();
+//}
+//
+//DWARFDebugPubnames*
+//SymbolFileDWARF::DebugPubtypes()
+//{
+// if (m_pubtypes.get() == NULL)
+// {
+// Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+// const DataExtractor &debug_pubtypes_data = get_debug_pubtypes_data();
+// if (debug_pubtypes_data.GetByteSize() > 0)
+// {
+// // Pass false to indicate this is a pubnames section
+// m_pubtypes.reset(new DWARFDebugPubnames());
+// if (m_pubtypes.get())
+// m_pubtypes->Extract(debug_pubtypes_data);
+// }
+// }
+// return m_pubtypes.get();
+//}
+//
+
+bool
+SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit* cu, CompUnitSP& compile_unit_sp)
+{
+ if (cu != NULL)
+ {
+ const DWARFDebugInfoEntry * cu_die = cu->GetCompileUnitDIEOnly ();
+ if (cu_die)
+ {
+ const char * cu_die_name = cu_die->GetName(this, cu);
+ const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, cu, DW_AT_comp_dir, NULL);
+ Language::Type language = (Language::Type)cu_die->GetAttributeValueAsUnsigned(this, cu, DW_AT_language, 0);
+ if (cu_die_name)
+ {
+ if (cu_die_name[0] == '/' || cu_comp_dir == NULL && cu_comp_dir[0])
+ {
+ compile_unit_sp.reset(new CompileUnit(m_obj_file->GetModule(), cu, cu_die_name, cu->GetOffset(), language));
+ }
+ else
+ {
+ std::string fullpath(cu_comp_dir);
+ if (*fullpath.rbegin() != '/')
+ fullpath += '/';
+ fullpath += cu_die_name;
+
+ compile_unit_sp.reset(new CompileUnit(m_obj_file->GetModule(), cu, fullpath.c_str(), cu->GetOffset(), language));
+ }
+
+ if (compile_unit_sp.get())
+ {
+ cu->SetUserData(compile_unit_sp.get());
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+#if defined LLDB_SYMBOL_FILE_DWARF_SHRINK_TEST
+
+void
+SymbolFileDWARF::ShrinkDSYM(CompileUnit *dc_cu, DWARFCompileUnit *dw_cu, const FileSpec& cu_fspec, const FileSpec& base_types_fspec, FSToDIES& fs_to_dies, const DWARFDebugInfoEntry *die)
+{
+ while (die != NULL)
+ {
+ dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_base_type:
+ // Put all base types into the base type compile unit
+ fs_to_dies[base_types_fspec].Insert(die);
+ break;
+
+ default:
+ {
+ uint32_t decl_file = die->GetAttributeValueAsUnsigned(this, dw_cu, DW_AT_decl_file, 0);
+ if (decl_file)
+ {
+ fs_to_dies[dc_cu->GetSupportFiles().GetFileSpecAtIndex(decl_file)].Insert(die);
+ }
+ else
+ {
+ // add this to the current compile unit
+ fs_to_dies[cu_fspec].Insert(die);
+ }
+ }
+ break;
+ }
+
+ die = die->GetSibling();
+ }
+}
+
+
+
+#endif
+
+uint32_t
+SymbolFileDWARF::GetNumCompileUnits()
+{
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ {
+#if defined LLDB_SYMBOL_FILE_DWARF_SHRINK_TEST
+ uint32_t cu_idx;
+ FSToDIES fs_to_dies;
+
+ FileSpec base_type_fspec("DW_TAG_base_type");
+ const uint32_t num_comp_units = info->GetNumCompileUnits();
+
+ for (cu_idx=0; cu_idx < num_comp_units; ++cu_idx)
+ {
+ DWARFCompileUnit* cu = info->GetCompileUnitAtIndex(cu_idx);
+ if (cu != NULL)
+ {
+ const DWARFDebugInfoEntry *cu_die = cu->DIE();
+ if (cu_die)
+ {
+ CompUnitSP dc_cu_sp;
+ ParseCompileUnit(cu, dc_cu_sp);
+ if (dc_cu_sp.get())
+ {
+ FileSpec cu_fspec(*dc_cu_sp.get());
+
+ ShrinkDSYM(dc_cu_sp.get(), cu, cu_fspec, base_type_fspec, fs_to_dies, cu->DIE()->GetFirstChild());
+ }
+ }
+ }
+ }
+
+ Stream strm(stdout);
+ FSToDIES::const_iterator pos, end = fs_to_dies.end();
+ for (pos = fs_to_dies.begin(); pos != end; ++pos)
+ {
+ strm << "\n\nMinimal Compile Unit: " << pos->first << ":\n";
+ const DWARFDIECollection& dies = pos->second;
+ dies.Dump(strm, NULL);
+ }
+ return num_comp_units;
+#else
+ return info->GetNumCompileUnits();
+#endif
+ }
+ return 0;
+}
+
+CompUnitSP
+SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx)
+{
+ CompUnitSP comp_unit;
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ {
+ DWARFCompileUnit* cu = info->GetCompileUnitAtIndex(cu_idx);
+ if (cu != NULL)
+ {
+ // Our symbol vendor shouldn't be asking us to add a compile unit that
+ // has already been added to it, which this DWARF plug-in knows as it
+ // stores the lldb compile unit (CompileUnit) pointer in each
+ // DWARFCompileUnit object when it gets added.
+ assert(cu->GetUserData() == NULL);
+ ParseCompileUnit(cu, comp_unit);
+ }
+ }
+ return comp_unit;
+}
+
+static void
+AddRangesToBlock
+(
+ BlockList& blocks,
+ lldb::user_id_t blockID,
+ DWARFDebugRanges::RangeList& ranges,
+ addr_t block_base_addr
+)
+{
+ ranges.SubtractOffset (block_base_addr);
+ size_t range_idx = 0;
+ const DWARFDebugRanges::Range *debug_range;
+ for (range_idx = 0; (debug_range = ranges.RangeAtIndex(range_idx)) != NULL; range_idx++)
+ {
+ blocks.AddRange(blockID, debug_range->begin_offset, debug_range->end_offset);
+ }
+}
+
+
+Function *
+SymbolFileDWARF::ParseCompileUnitFunction (const SymbolContext& sc, const 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;
+
+ // Parse the function prototype as a type that can then be added to concrete function instance
+ ParseTypes (sc, dwarf_cu, die, false, false);
+ //FixupTypes();
+
+ 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.LowestAddress(0);
+ lldb::addr_t highest_func_addr = func_ranges.HighestAddress(0);
+ if (lowest_func_addr != LLDB_INVALID_ADDRESS && lowest_func_addr <= highest_func_addr)
+ {
+ func_range.GetBaseAddress().ResolveAddressUsingFileSections (lowest_func_addr, m_obj_file->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(mangled, true);
+ else if (name)
+ func_name.SetValue(name, false);
+
+ FunctionSP func_sp;
+ std::auto_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));
+
+ Type *func_type = NULL;
+
+ if (die->GetUserData() != DIE_IS_BEING_PARSED)
+ func_type = (Type*)die->GetUserData();
+
+ assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED);
+
+ func_range.GetBaseAddress().ResolveLinkedAddress();
+
+ func_sp.reset(new Function (sc.comp_unit,
+ die->GetOffset(), // UserID is the DIE offset
+ die->GetOffset(),
+ func_name,
+ func_type,
+ func_range)); // first address range
+
+ if (func_sp.get() != NULL)
+ {
+ func_sp->GetFrameBaseExpression() = frame_base;
+ sc.comp_unit->AddFunction(func_sp);
+ return func_sp.get();
+ }
+ }
+ }
+ return NULL;
+}
+
+size_t
+SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc)
+{
+ assert (sc.comp_unit);
+ size_t functions_added = 0;
+ const DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID());
+ if (dwarf_cu)
+ {
+ DWARFDIECollection function_dies;
+ const size_t num_funtions = dwarf_cu->AppendDIEsWithTag (DW_TAG_subprogram, function_dies);
+ size_t func_idx;
+ for (func_idx = 0; func_idx < num_funtions; ++func_idx)
+ {
+ const DWARFDebugInfoEntry *die = function_dies.GetDIEPtrAtIndex(func_idx);
+ if (sc.comp_unit->FindFunctionByUID (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* cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID());
+ assert (cu);
+ const DWARFDebugInfoEntry * cu_die = cu->GetCompileUnitDIEOnly();
+
+ if (cu_die)
+ {
+ const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, cu, DW_AT_comp_dir, NULL);
+ dw_offset_t stmt_list = cu_die->GetAttributeValueAsUnsigned(this, 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(get_debug_line_data(), cu_comp_dir, stmt_list, support_files);
+ }
+ return false;
+}
+
+struct ParseDWARFLineTableCallbackInfo
+{
+ LineTable* line_table;
+ const SectionList *section_list;
+ lldb::addr_t prev_sect_file_base_addr;
+ lldb::addr_t curr_sect_file_base_addr;
+ bool is_oso_for_debug_map;
+ bool prev_in_final_executable;
+ DWARFDebugLine::Row prev_row;
+ SectionSP prev_section_sp;
+ SectionSP curr_section_sp;
+};
+
+//----------------------------------------------------------------------
+// ParseStatementTableCallback
+//----------------------------------------------------------------------
+static void
+ParseDWARFLineTableCallback(dw_offset_t offset, const DWARFDebugLine::State& state, void* userData)
+{
+ LineTable* line_table = ((ParseDWARFLineTableCallbackInfo*)userData)->line_table;
+ 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;
+ // We have a new row, lets append it
+
+ if (info->curr_section_sp.get() == NULL || info->curr_section_sp->ContainsFileAddress(state.address) == false)
+ {
+ info->prev_section_sp = info->curr_section_sp;
+ info->prev_sect_file_base_addr = info->curr_sect_file_base_addr;
+ // If this is an end sequence entry, then we subtract one from the
+ // address to make sure we get an address that is not the end of
+ // a section.
+ if (state.end_sequence && state.address != 0)
+ info->curr_section_sp = info->section_list->FindSectionContainingFileAddress (state.address - 1);
+ else
+ info->curr_section_sp = info->section_list->FindSectionContainingFileAddress (state.address);
+
+ if (info->curr_section_sp.get())
+ info->curr_sect_file_base_addr = info->curr_section_sp->GetFileAddress ();
+ else
+ info->curr_sect_file_base_addr = 0;
+ }
+ if (info->curr_section_sp.get())
+ {
+ lldb::addr_t curr_line_section_offset = state.address - info->curr_sect_file_base_addr;
+ // Check for the fancy section magic to determine if we
+
+ if (info->is_oso_for_debug_map)
+ {
+ // When this is a debug map object file that contains DWARF
+ // (referenced from an N_OSO debug map nlist entry) we will have
+ // a file address in the file range for our section from the
+ // original .o file, and a load address in the executable that
+ // contains the debug map.
+ //
+ // If the sections for the file range and load range are
+ // different, we have a remapped section for the function and
+ // this address is resolved. If they are the same, then the
+ // function for this address didn't make it into the final
+ // executable.
+ bool curr_in_final_executable = info->curr_section_sp->GetLinkedSection () != NULL;
+
+ // If we are doing DWARF with debug map, then we need to carefully
+ // add each line table entry as there may be gaps as functions
+ // get moved around or removed.
+ if (!info->prev_row.end_sequence && info->prev_section_sp.get())
+ {
+ if (info->prev_in_final_executable)
+ {
+ bool terminate_previous_entry = false;
+ if (!curr_in_final_executable)
+ {
+ // Check for the case where the previous line entry
+ // in a function made it into the final executable,
+ // yet the current line entry falls in a function
+ // that didn't. The line table used to be contiguous
+ // through this address range but now it isn't. We
+ // need to terminate the previous line entry so
+ // that we can reconstruct the line range correctly
+ // for it and to keep the line table correct.
+ terminate_previous_entry = true;
+ }
+ else if (info->curr_section_sp.get() != info->prev_section_sp.get())
+ {
+ // Check for cases where the line entries used to be
+ // contiguous address ranges, but now they aren't.
+ // This can happen when order files specify the
+ // ordering of the functions.
+ lldb::addr_t prev_line_section_offset = info->prev_row.address - info->prev_sect_file_base_addr;
+ Section *curr_sect = info->curr_section_sp.get();
+ Section *prev_sect = info->prev_section_sp.get();
+ assert (curr_sect->GetLinkedSection());
+ assert (prev_sect->GetLinkedSection());
+ lldb::addr_t object_file_addr_delta = state.address - info->prev_row.address;
+ lldb::addr_t curr_linked_file_addr = curr_sect->GetLinkedFileAddress() + curr_line_section_offset;
+ lldb::addr_t prev_linked_file_addr = prev_sect->GetLinkedFileAddress() + prev_line_section_offset;
+ lldb::addr_t linked_file_addr_delta = curr_linked_file_addr - prev_linked_file_addr;
+ if (object_file_addr_delta != linked_file_addr_delta)
+ terminate_previous_entry = true;
+ }
+
+ if (terminate_previous_entry)
+ {
+ line_table->InsertLineEntry (info->prev_section_sp,
+ state.address - info->prev_sect_file_base_addr,
+ info->prev_row.line,
+ info->prev_row.column,
+ info->prev_row.file,
+ false, // is_stmt
+ false, // basic_block
+ false, // state.prologue_end
+ false, // state.epilogue_begin
+ true); // end_sequence);
+ }
+ }
+ }
+
+ if (curr_in_final_executable)
+ {
+ line_table->InsertLineEntry (info->curr_section_sp,
+ curr_line_section_offset,
+ state.line,
+ state.column,
+ state.file,
+ state.is_stmt,
+ state.basic_block,
+ state.prologue_end,
+ state.epilogue_begin,
+ state.end_sequence);
+ info->prev_section_sp = info->curr_section_sp;
+ }
+ else
+ {
+ // If the current address didn't make it into the final
+ // executable, the current section will be the __text
+ // segment in the .o file, so we need to clear this so
+ // we can catch the next function that did make it into
+ // the final executable.
+ info->prev_section_sp.reset();
+ info->curr_section_sp.reset();
+ }
+
+ info->prev_in_final_executable = curr_in_final_executable;
+ }
+ else
+ {
+ // We are not in an object file that contains DWARF for an
+ // N_OSO, this is just a normal DWARF file. The DWARF spec
+ // guarantees that the addresses will be in increasing order
+ // so, since we store line tables in file address order, we
+ // can always just append the line entry without needing to
+ // search for the correct insertion point (we don't need to
+ // use LineEntry::InsertLineEntry()).
+ line_table->AppendLineEntry (info->curr_section_sp,
+ curr_line_section_offset,
+ state.line,
+ state.column,
+ state.file,
+ state.is_stmt,
+ state.basic_block,
+ state.prologue_end,
+ state.epilogue_begin,
+ state.end_sequence);
+ }
+ }
+
+ info->prev_row = state;
+ }
+}
+
+bool
+SymbolFileDWARF::ParseCompileUnitLineTable (const SymbolContext &sc)
+{
+ assert (sc.comp_unit);
+ if (sc.comp_unit->GetLineTable() != NULL)
+ return true;
+
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID());
+ if (dwarf_cu)
+ {
+ const DWARFDebugInfoEntry *dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly();
+ 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::auto_ptr<LineTable> line_table_ap(new LineTable(sc.comp_unit));
+ if (line_table_ap.get())
+ {
+ ParseDWARFLineTableCallbackInfo info = { line_table_ap.get(), m_obj_file->GetSectionList(), 0, 0, m_flags.IsSet (flagsDWARFIsOSOForDebugMap), false};
+ uint32_t offset = cu_line_offset;
+ DWARFDebugLine::ParseStatementTable(get_debug_line_data(), &offset, ParseDWARFLineTableCallback, &info);
+ sc.comp_unit->SetLineTable(line_table_ap.release());
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+size_t
+SymbolFileDWARF::ParseFunctionBlocks
+(
+ const SymbolContext& sc,
+ lldb::user_id_t parentBlockID,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ addr_t subprogram_low_pc,
+ bool parse_siblings,
+ bool parse_children
+)
+{
+ size_t blocks_added = 0;
+ while (die != NULL)
+ {
+ dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ {
+ DWARFDebugRanges::RangeList ranges;
+ const char *name = NULL;
+ const char *mangled_name = NULL;
+ BlockList& blocks = sc.function->GetBlocks(false);
+
+ lldb::user_id_t blockID = blocks.AddChild(parentBlockID, die->GetOffset());
+ 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.LowestAddress(0);
+ }
+
+ AddRangesToBlock (blocks, blockID, ranges, subprogram_low_pc);
+
+ if (tag != DW_TAG_subprogram && (name != NULL || mangled_name != NULL))
+ {
+ std::auto_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::auto_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));
+
+ blocks.SetInlinedFunctionInfo(blockID, name, mangled_name, decl_ap.get(), call_ap.get());
+ }
+
+ ++blocks_added;
+
+ if (parse_children && die->HasChildren())
+ {
+ blocks_added += ParseFunctionBlocks(sc, blockID, dwarf_cu, die->GetFirstChild(), subprogram_low_pc, true, true);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (parse_siblings)
+ die = die->GetSibling();
+ else
+ die = NULL;
+ }
+ return blocks_added;
+}
+
+size_t
+SymbolFileDWARF::ParseChildMembers
+(
+ const SymbolContext& sc,
+ TypeSP& type_sp,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ std::vector<clang::CXXBaseSpecifier *>& base_classes,
+ std::vector<int>& member_accessibilities,
+ int& default_accessibility,
+ bool &is_a_class
+)
+{
+ if (parent_die == NULL)
+ return 0;
+
+ TypeList* type_list = m_obj_file->GetModule()->GetTypeList();
+
+ size_t count = 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_member:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_attributes > 0)
+ {
+ Declaration decl;
+ DWARFExpression location;
+ const char *name = NULL;
+ lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
+ uint32_t accessibility = clang::AS_none;
+ off_t member_offset = 0;
+ size_t byte_size = 0;
+ size_t bit_offset = 0;
+ size_t bit_size = 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_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, NULL, debug_info_data, NULL, NULL, block_offset, block_length, eRegisterKindDWARF, &initialValue, memberOffset, NULL))
+ {
+ member_offset = memberOffset.ResolveValue(NULL, NULL).UInt();
+ }
+ }
+ break;
+
+ case DW_AT_accessibility: accessibility = DwarfToClangAccessibility (form_value.Unsigned()); break;
+ case DW_AT_declaration:
+ case DW_AT_description:
+ case DW_AT_mutable:
+ case DW_AT_visibility:
+ default:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ Type *member_type = ResolveTypeUID(encoding_uid);
+ assert(member_type);
+ if (accessibility == clang::AS_none)
+ accessibility = default_accessibility;
+ member_accessibilities.push_back(accessibility);
+
+ type_list->GetClangASTContext().AddFieldToRecordType (type_sp->GetOpaqueClangQualType(), name, member_type->GetOpaqueClangQualType(), accessibility, bit_size);
+ }
+ }
+ break;
+
+ case DW_TAG_subprogram:
+ {
+ is_a_class = true;
+ if (default_accessibility == clang::AS_none)
+ default_accessibility = clang::AS_private;
+ // TODO: implement DW_TAG_subprogram type parsing
+// UserDefTypeChildInfo method_info(die->GetOffset());
+//
+// FunctionSP func_sp (sc.comp_unit->FindFunctionByUID (die->GetOffset()));
+// if (func_sp.get() == NULL)
+// ParseCompileUnitFunction(sc, dwarf_cu, die);
+//
+// method_info.SetEncodingTypeUID(die->GetOffset());
+// struct_udt->AddMethod(method_info);
+ }
+ break;
+
+ case DW_TAG_inheritance:
+ {
+ is_a_class = true;
+ if (default_accessibility == clang::AS_none)
+ default_accessibility = clang::AS_private;
+ // TODO: implement DW_TAG_inheritance type parsing
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_attributes > 0)
+ {
+ Declaration decl;
+ DWARFExpression location;
+ lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
+ uint32_t accessibility = default_accessibility;
+ bool is_virtual = false;
+ bool is_base_of_class = true;
+ off_t member_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, debug_info_data, NULL, NULL, block_offset, block_length, eRegisterKindDWARF, &initialValue, memberOffset, NULL))
+ {
+ member_offset = memberOffset.ResolveValue(NULL, NULL).UInt();
+ }
+ }
+ break;
+
+ case DW_AT_accessibility:
+ accessibility = DwarfToClangAccessibility(form_value.Unsigned());
+ break;
+
+ case DW_AT_virtuality: is_virtual = form_value.Unsigned() != 0; break;
+ default:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ Type *base_class_dctype = ResolveTypeUID(encoding_uid);
+ assert(base_class_dctype);
+ base_classes.push_back (type_list->GetClangASTContext().CreateBaseClassSpecifier (base_class_dctype->GetOpaqueClangQualType(), accessibility, is_virtual, is_base_of_class));
+ assert(base_classes.back());
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return count;
+}
+
+
+clang::DeclContext*
+SymbolFileDWARF::GetClangDeclContextForTypeUID (lldb::user_id_t type_uid)
+{
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(type_uid, &cu_sp);
+ if (die)
+ return GetClangDeclContextForDIE (cu_sp.get(), die);
+ }
+ return NULL;
+}
+
+Type*
+SymbolFileDWARF::ResolveTypeUID(lldb::user_id_t type_uid)
+{
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ const DWARFDebugInfoEntry* type_die = debug_info->GetDIEPtr(type_uid, NULL);
+ if (type_die != NULL)
+ {
+ void *type = type_die->GetUserData();
+ if (type == NULL)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(type_uid, &cu_sp);
+ if (die != NULL)
+ {
+ TypeSP owning_type_sp;
+ TypeSP type_sp(GetTypeForDIE(cu_sp.get(), die, owning_type_sp, 0, 0));
+ }
+ type = type_die->GetUserData();
+ }
+ if (type != DIE_IS_BEING_PARSED)
+ return (Type *)type;
+ }
+ }
+ return NULL;
+}
+
+CompileUnit*
+SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit* cu, uint32_t cu_idx)
+{
+ // Check if the symbol vendor already knows about this compile unit?
+ if (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.
+ CompUnitSP dc_cu;
+ ParseCompileUnit(cu, dc_cu);
+ if (dc_cu.get())
+ {
+ // Figure out the compile unit index if we weren't given one
+ if (cu_idx == UINT_MAX)
+ DebugInfo()->GetCompileUnit(cu->GetOffset(), &cu_idx);
+
+ m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(dc_cu, cu_idx);
+ }
+ }
+ return (CompileUnit*)cu->GetUserData();
+}
+
+bool
+SymbolFileDWARF::GetFunction (DWARFCompileUnit* cu, const DWARFDebugInfoEntry* func_die, SymbolContext& sc)
+{
+ sc.Clear();
+ // Check if the symbol vendor already knows about this compile unit?
+ sc.module_sp = m_obj_file->GetModule()->GetSP();
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, UINT_MAX);
+
+ sc.function = sc.comp_unit->FindFunctionByUID (func_die->GetOffset()).get();
+ if (sc.function == NULL)
+ sc.function = ParseCompileUnitFunction(sc, cu, func_die);
+
+ return sc.function != NULL;
+}
+
+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%llx }, resolve_scope = 0x%8.8x)",
+ so_addr.GetSection(),
+ 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();
+
+ DWARFDebugAranges* debug_aranges = DebugAranges();
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_aranges)
+ {
+ dw_offset_t cu_offset = debug_aranges->FindAddress(file_vm_addr);
+ if (cu_offset != DW_INVALID_OFFSET)
+ {
+ uint32_t cu_idx;
+ DWARFCompileUnit* cu = debug_info->GetCompileUnit(cu_offset, &cu_idx).get();
+ if (cu)
+ {
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, cu_idx);
+ assert(sc.comp_unit != NULL);
+ resolved |= eSymbolContextCompUnit;
+
+ if (resolve_scope & eSymbolContextLineEntry)
+ {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+ if (line_table == NULL)
+ {
+ if (ParseCompileUnitLineTable(sc))
+ line_table = sc.comp_unit->GetLineTable();
+ }
+ if (line_table != NULL)
+ {
+ if (so_addr.IsLinkedAddress())
+ {
+ Address linked_addr (so_addr);
+ linked_addr.ResolveLinkedAddress();
+ if (line_table->FindLineEntryByAddress (linked_addr, sc.line_entry))
+ {
+ resolved |= eSymbolContextLineEntry;
+ }
+ }
+ else if (line_table->FindLineEntryByAddress (so_addr, sc.line_entry))
+ {
+ resolved |= eSymbolContextLineEntry;
+ }
+ }
+ }
+
+ if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock))
+ {
+ DWARFDebugInfoEntry *function_die = NULL;
+ DWARFDebugInfoEntry *block_die = NULL;
+ if (resolve_scope & eSymbolContextBlock)
+ {
+ cu->LookupAddress(file_vm_addr, &function_die, &block_die);
+ }
+ else
+ {
+ cu->LookupAddress(file_vm_addr, &function_die, NULL);
+ }
+
+ if (function_die != NULL)
+ {
+ sc.function = sc.comp_unit->FindFunctionByUID (function_die->GetOffset()).get();
+ if (sc.function == NULL)
+ sc.function = ParseCompileUnitFunction(sc, cu, function_die);
+ }
+
+ if (sc.function != NULL)
+ {
+ resolved |= eSymbolContextFunction;
+
+ if (resolve_scope & eSymbolContextBlock)
+ {
+ BlockList& blocks = sc.function->GetBlocks(true);
+
+ if (block_die != NULL)
+ sc.block = blocks.GetBlockByID(block_die->GetOffset());
+ else
+ sc.block = blocks.GetBlockByID(function_die->GetOffset());
+ if (sc.block)
+ resolved |= eSymbolContextBlock;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ 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* cu = NULL;
+
+ for (cu_idx = 0; (cu = debug_info->GetCompileUnitAtIndex(cu_idx)) != NULL; ++cu_idx)
+ {
+ CompileUnit *dc_cu = GetCompUnitForDWARFCompUnit(cu, cu_idx);
+ bool file_spec_matches_cu_file_spec = dc_cu != NULL && FileSpec::Compare(file_spec, *dc_cu, false) == 0;
+ if (check_inlines || file_spec_matches_cu_file_spec)
+ {
+ SymbolContext sc (m_obj_file->GetModule());
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, cu_idx);
+ assert(sc.comp_unit != NULL);
+
+ 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);
+ 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);
+
+ 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 != UINT_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;
+ cu->LookupAddress(file_vm_addr, &function_die, resolve_scope & eSymbolContextBlock ? &block_die : NULL);
+
+ if (function_die != NULL)
+ {
+ sc.function = sc.comp_unit->FindFunctionByUID (function_die->GetOffset()).get();
+ if (sc.function == NULL)
+ sc.function = ParseCompileUnitFunction(sc, cu, function_die);
+ }
+
+ if (sc.function != NULL)
+ {
+ BlockList& blocks = sc.function->GetBlocks(true);
+
+ if (block_die != NULL)
+ sc.block = blocks.GetBlockByID(block_die->GetOffset());
+ else
+ sc.block = blocks.GetBlockByID(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* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+
+ bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1;
+
+ cu->Index (m_name_to_function_die,
+ m_name_to_inlined_die,
+ m_name_to_global_die,
+ m_name_to_type_die);
+
+ // Keep memory down by clearing DIEs if this generate function
+ // caused them to be parsed
+ if (clear_dies)
+ cu->ClearDIEs (true);
+ }
+
+ m_name_to_function_die.Sort();
+ m_name_to_inlined_die.Sort();
+ m_name_to_global_die.Sort();
+ m_name_to_type_die.Sort();
+ }
+}
+
+uint32_t
+SymbolFileDWARF::FindGlobalVariables (const ConstString &name, bool append, uint32_t max_matches, VariableList& variables)
+{
+ std::vector<dw_offset_t> die_offsets;
+
+ // 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();
+
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ const UniqueCStringMap<dw_offset_t>::Entry *entry;
+
+ for (entry = m_name_to_global_die.FindFirstValueForName (name.AsCString());
+ entry != NULL;
+ entry = m_name_to_global_die.FindNextValueForName (name.AsCString(), entry))
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr (entry->value, &cu_sp);
+ DWARFCompileUnit* cu = cu_sp.get();
+ if (die)
+ {
+ SymbolContext sc;
+ sc.module_sp = m_obj_file->GetModule()->GetSP();
+ assert (sc.module_sp);
+
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, UINT_MAX);
+ assert(sc.comp_unit != NULL);
+
+ ParseVariables(sc, cu_sp.get(), die, false, false, &variables);
+
+ if (variables.GetSize() - original_size >= max_matches)
+ break;
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return variables.GetSize() - original_size;
+}
+
+uint32_t
+SymbolFileDWARF::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ std::vector<dw_offset_t> die_offsets;
+
+ // 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();
+
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ // Create the pubnames information so we can quickly lookup external symbols by name
+ const size_t num_entries = m_name_to_global_die.GetSize();
+ for (size_t i=0; i<num_entries; i++)
+ {
+ if (!regex.Execute(m_name_to_global_die.GetCStringAtIndex (i)))
+ continue;
+
+ const dw_offset_t die_offset = *m_name_to_global_die.GetValueAtIndex (i);
+
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr (die_offset, &cu_sp);
+ DWARFCompileUnit* cu = cu_sp.get();
+ if (die)
+ {
+ SymbolContext sc;
+ sc.module_sp = m_obj_file->GetModule()->GetSP();
+ assert (sc.module_sp);
+
+
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, UINT_MAX);
+ assert(sc.comp_unit != NULL);
+
+ ParseVariables(sc, cu_sp.get(), die, false, false, &variables);
+
+ if (variables.GetSize() - original_size >= max_matches)
+ break;
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return variables.GetSize() - original_size;
+}
+
+
+uint32_t
+SymbolFileDWARF::FindFunctions(const ConstString &name, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::FindFunctions (name = '%s')",
+ name.AsCString());
+
+ std::vector<dw_offset_t> die_offsets;
+
+ // 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();
+
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ const UniqueCStringMap<dw_offset_t>::Entry *entry;
+
+ SymbolContext sc;
+ for (entry = m_name_to_function_die.FindFirstValueForName (name.AsCString());
+ entry != NULL;
+ entry = m_name_to_function_die.FindNextValueForName (name.AsCString(), entry))
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr (entry->value, &cu_sp);
+ if (die)
+ {
+ if (GetFunction (cu_sp.get(), die, sc))
+ {
+ // We found the function, so we should find the line table
+ // and line table entry as well
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+ if (line_table == NULL)
+ {
+ if (ParseCompileUnitLineTable(sc))
+ line_table = sc.comp_unit->GetLineTable();
+ }
+ if (line_table != NULL)
+ line_table->FindLineEntryByAddress (sc.function->GetAddressRange().GetBaseAddress(), sc.line_entry);
+
+ sc_list.Append(sc);
+ }
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return sc_list.GetSize() - original_size;
+}
+
+
+uint32_t
+SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::FindFunctions (regex = '%s')",
+ regex.GetText());
+
+ std::vector<dw_offset_t> die_offsets;
+
+ // 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();
+
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ // Create the pubnames information so we can quickly lookup external symbols by name
+ // Create the pubnames information so we can quickly lookup external symbols by name
+ const size_t num_entries = m_name_to_function_die.GetSize();
+ SymbolContext sc;
+ for (size_t i=0; i<num_entries; i++)
+ {
+ if (!regex.Execute(m_name_to_function_die.GetCStringAtIndex (i)))
+ continue;
+
+ const dw_offset_t die_offset = *m_name_to_function_die.GetValueAtIndex (i);
+
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr (die_offset, &cu_sp);
+ if (die)
+ {
+ if (GetFunction (cu_sp.get(), die, sc))
+ {
+ // We found the function, so we should find the line table
+ // and line table entry as well
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+ if (line_table == NULL)
+ {
+ if (ParseCompileUnitLineTable(sc))
+ line_table = sc.comp_unit->GetLineTable();
+ }
+ if (line_table != NULL)
+ line_table->FindLineEntryByAddress (sc.function->GetAddressRange().GetBaseAddress(), sc.line_entry);
+
+
+ sc_list.Append(sc);
+ }
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return sc_list.GetSize() - original_size;
+}
+
+#if 0
+uint32_t
+SymbolFileDWARF::FindTypes(const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+{
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ types.Clear();
+
+ // Create the pubnames information so we can quickly lookup external symbols by name
+ DWARFDebugPubnames* pubtypes = DebugPubtypes();
+ if (pubtypes)
+ {
+ std::vector<dw_offset_t> die_offsets;
+ if (!pubtypes->Find(name.AsCString(), false, die_offsets))
+ {
+ DWARFDebugPubnames* pub_base_types = DebugPubBaseTypes();
+ if (pub_base_types && !pub_base_types->Find(name.AsCString(), false, die_offsets))
+ return 0;
+ }
+ return FindTypes(die_offsets, max_matches, encoding, udt_uid, types);
+ }
+ return 0;
+}
+
+
+uint32_t
+SymbolFileDWARF::FindTypes(const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+{
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ types.Clear();
+
+ // Create the pubnames information so we can quickly lookup external symbols by name
+ DWARFDebugPubnames* pubtypes = DebugPubtypes();
+ if (pubtypes)
+ {
+ std::vector<dw_offset_t> die_offsets;
+ if (!pubtypes->Find(regex, die_offsets))
+ {
+ DWARFDebugPubnames* pub_base_types = DebugPubBaseTypes();
+ if (pub_base_types && !pub_base_types->Find(regex, die_offsets))
+ return 0;
+ }
+
+ return FindTypes(die_offsets, max_matches, encoding, udt_uid, types);
+ }
+
+ return 0;
+}
+
+
+
+uint32_t
+SymbolFileDWARF::FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, 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.Size();
+
+ 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)
+ {
+ dw_offset_t die_offset = die_offsets[i];
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr(die_offset, &cu_sp);
+
+ assert(die != NULL);
+
+ bool get_type_for_die = true;
+ if (encoding)
+ {
+ // Check if this type has already been uniqued and registers with the module?
+ Type* type = (Type*)die->GetUserData();
+ if (type != NULL && type != DIE_IS_BEING_PARSED)
+ {
+ get_type_for_die = type->GetEncoding() == encoding;
+ }
+ else
+ {
+ dw_tag_t tag = die->Tag();
+ switch (encoding)
+ {
+ case Type::address:
+ case Type::boolean:
+ case Type::complex_float:
+ case Type::float_type:
+ case Type::signed_int:
+ case Type::signed_char:
+ case Type::unsigned_int:
+ case Type::unsigned_char:
+ case Type::imaginary_float:
+ case Type::packed_decimal:
+ case Type::numeric_string:
+ case Type::edited_string:
+ case Type::signed_fixed:
+ case Type::unsigned_fixed:
+ case Type::decimal_float:
+ if (tag != DW_TAG_base_type)
+ get_type_for_die = false;
+ else
+ {
+ if (die->GetAttributeValueAsUnsigned(this, cu_sp.get(), DW_AT_encoding, Type::invalid) != encoding)
+ get_type_for_die = false;
+ }
+ break;
+
+ case Type::indirect_const: get_type_for_die = tag == DW_TAG_const_type; break;
+ case Type::indirect_restrict: get_type_for_die = tag == DW_TAG_restrict_type; break;
+ case Type::indirect_volatile: get_type_for_die = tag == DW_TAG_volatile_type; break;
+ case Type::indirect_typedef: get_type_for_die = tag == DW_TAG_typedef; break;
+ case Type::indirect_pointer: get_type_for_die = tag == DW_TAG_pointer_type; break;
+ case Type::indirect_reference: get_type_for_die = tag == DW_TAG_reference_type; break;
+
+ case Type::user_defined_type:
+ switch (tag)
+ {
+ case DW_TAG_array_type:
+ get_type_for_die = UserDefTypeArray::OwnsUserDefTypeUID(udt_uid);
+ break;
+
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ get_type_for_die = UserDefTypeStruct::OwnsUserDefTypeUID(udt_uid);
+ break;
+
+ case DW_TAG_enumeration_type:
+ get_type_for_die = UserDefTypeEnum::OwnsUserDefTypeUID(udt_uid);
+ break;
+
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ get_type_for_die = UserDefTypeFunction::OwnsUserDefTypeUID(udt_uid);
+ break;
+ }
+ }
+ }
+ }
+
+ if (get_type_for_die)
+ {
+ TypeSP owning_type_sp;
+ TypeSP type_sp(GetTypeForDIE(cu_sp.get(), die, owning_type_sp, NULL, 0, 0));
+
+ if (type_sp.get())
+ {
+ // See if we are filtering results based on encoding?
+ bool add_type = (encoding == Type::invalid);
+ if (!add_type)
+ {
+ // We are filtering base on encoding, so lets check the resulting type encoding
+ add_type = (encoding == type_sp->GetEncoding());
+ if (add_type)
+ {
+ // The type encoding matches, if this is a user defined type, lets
+ // make sure the exact user define type uid matches if one was provided
+ if (encoding == Type::user_defined_type && udt_uid != LLDB_INVALID_UID)
+ {
+ UserDefType* udt = type_sp->GetUserDefinedType().get();
+ if (udt)
+ add_type = udt->UserDefinedTypeUID() == udt_uid;
+ }
+ }
+ }
+ // Add the type to our list as long as everything matched
+ if (add_type)
+ {
+ types.InsertUnique(type_sp);
+ if (++num_matches >= max_matches)
+ break;
+ }
+ }
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return types.Size() - original_size;
+}
+
+#endif
+
+
+size_t
+SymbolFileDWARF::ParseChildParameters
+(
+ const SymbolContext& sc,
+ TypeSP& type_sp,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ TypeList* type_list,
+ std::vector<void *>& function_param_types,
+ std::vector<clang::ParmVarDecl*>& function_param_decls
+)
+{
+ if (parent_die == NULL)
+ return 0;
+
+ size_t count = 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, attributes);
+ if (num_attributes > 0)
+ {
+ const char *name = NULL;
+ Declaration decl;
+ dw_offset_t param_type_die_offset = DW_INVALID_OFFSET;
+ // one of None, Auto, Register, Extern, Static, PrivateExtern
+
+ clang::VarDecl::StorageClass storage = clang::VarDecl::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_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_artificial:
+ 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;
+ }
+ }
+ }
+ Type *dc_type = ResolveTypeUID(param_type_die_offset);
+ if (dc_type)
+ {
+ function_param_types.push_back (dc_type->GetOpaqueClangQualType());
+
+ clang::ParmVarDecl *param_var_decl = type_list->GetClangASTContext().CreateParmeterDeclaration (name, dc_type->GetOpaqueClangQualType(), storage);
+ assert(param_var_decl);
+ function_param_decls.push_back(param_var_decl);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return count;
+}
+
+size_t
+SymbolFileDWARF::ParseChildEnumerators
+(
+ const SymbolContext& sc,
+ TypeSP& type_sp,
+ void * enumerator_qual_type,
+ uint32_t enumerator_byte_size,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die
+)
+{
+ if (parent_die == NULL)
+ return 0;
+
+ size_t enumerators_added = 0;
+ const DWARFDebugInfoEntry *die;
+ 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, 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;
+ 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)
+ {
+ TypeList* type_list = m_obj_file->GetModule()->GetTypeList();
+ type_list->GetClangASTContext().AddEnumerationValueToEnumerationType (type_sp->GetOpaqueClangQualType(), enumerator_qual_type, decl, name, enum_value, enumerator_byte_size * 8);
+ ++enumerators_added;
+ }
+ }
+ }
+ }
+ return enumerators_added;
+}
+
+void
+SymbolFileDWARF::ParseChildArrayInfo
+(
+ const SymbolContext& sc,
+ const 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;
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ const dw_tag_t tag = die->Tag();
+ switch (tag)
+ {
+ case DW_TAG_enumerator:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_child_attributes > 0)
+ {
+ const char *name = NULL;
+ bool got_value = false;
+ int64_t enum_value = 0;
+
+ 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;
+ 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:
+ case DW_AT_decl_line:
+ case DW_AT_decl_column:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case DW_TAG_subrange_type:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_child_attributes > 0)
+ {
+ const char *name = NULL;
+ bool got_value = false;
+ uint64_t byte_size = 0;
+ int64_t enum_value = 0;
+ uint64_t num_elements = 0;
+ uint64_t lower_bound = 0;
+ uint64_t upper_bound = 0;
+ 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;
+ enum_value = form_value.Unsigned();
+ break;
+
+ case DW_AT_name:
+ name = form_value.AsCString(&get_debug_str_data());
+ 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_byte_size:
+ byte_size = form_value.Unsigned();
+ break;
+
+ case DW_AT_lower_bound:
+ lower_bound = form_value.Unsigned();
+ break;
+
+ case DW_AT_upper_bound:
+ upper_bound = form_value.Unsigned();
+ break;
+
+ default:
+ //printf("0x%8.8x: %-30s skipping attribute at 0x%8.8x: %s\n", die->GetOffset(), DW_TAG_value_to_name(tag), attributes.die_offsets[i], DW_AT_value_to_name(attr)); // remove this, debug only
+
+ 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 (upper_bound > lower_bound)
+ num_elements = upper_bound - lower_bound + 1;
+
+ if (num_elements > 0)
+ element_orders.push_back (num_elements);
+ }
+ }
+ break;
+ }
+ }
+}
+
+Type*
+SymbolFileDWARF::GetUniquedTypeForDIEOffset(dw_offset_t type_die_offset, TypeSP& owning_type_sp, int32_t child_type, uint32_t idx, bool safe)
+{
+ if (type_die_offset != DW_INVALID_OFFSET)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* type_die = DebugInfo()->GetDIEPtr(type_die_offset, &cu_sp);
+ assert(type_die != NULL);
+ GetTypeForDIE(cu_sp.get(), type_die, owning_type_sp, child_type, idx);
+ // Return the uniqued type if there is one
+ Type* type = (Type*)type_die->GetUserData();
+ if (type == DIE_IS_BEING_PARSED && safe)
+ return NULL;
+ return type;
+ }
+ return NULL;
+}
+
+TypeSP
+SymbolFileDWARF::GetTypeForDIE(DWARFCompileUnit *cu, const DWARFDebugInfoEntry* die, TypeSP& owning_type_sp, int32_t child_type, uint32_t idx)
+{
+ TypeSP type_sp;
+ if (die != NULL)
+ {
+ assert(cu != NULL);
+ Type *type_ptr = (Type *)die->GetUserData();
+ if (type_ptr == NULL)
+ {
+ SymbolContext sc(GetCompUnitForDWARFCompUnit(cu));
+ bool type_is_new = false;
+ type_sp = ParseType(sc, cu, die, type_is_new);
+ type_ptr = (Type *)die->GetUserData();
+ if (owning_type_sp.get() == NULL)
+ owning_type_sp = type_sp;
+ }
+ else if (type_ptr != DIE_IS_BEING_PARSED)
+ {
+ // Grab the existing type from the master types lists
+ type_sp = m_obj_file->GetModule()->GetTypeList()->FindType(type_ptr->GetID());
+ }
+
+ }
+ return type_sp;
+}
+
+clang::DeclContext *
+SymbolFileDWARF::GetClangDeclContextForDIEOffset (dw_offset_t die_offset)
+{
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr(die_offset, &cu_sp);
+ return GetClangDeclContextForDIE (cu_sp.get(), die);
+ }
+ return NULL;
+}
+
+
+
+clang::DeclContext *
+SymbolFileDWARF::GetClangDeclContextForDIE (const DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die)
+{
+ DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find(die);
+ if (pos != m_die_to_decl_ctx.end())
+ return pos->second;
+
+ while (die != NULL)
+ {
+ switch (die->Tag())
+ {
+ case DW_TAG_namespace:
+ {
+ const char *namespace_name = die->GetAttributeValueAsString(this, cu, DW_AT_name, NULL);
+ if (namespace_name)
+ {
+ TypeList* type_list = m_obj_file->GetModule()->GetTypeList();
+ assert(type_list);
+ Declaration decl; // TODO: fill in the decl object
+ clang::NamespaceDecl *namespace_decl = type_list->GetClangASTContext().GetUniqueNamespaceDeclaration (namespace_name, decl, GetClangDeclContextForDIE (cu, die->GetParent()));
+ if (namespace_decl)
+ m_die_to_decl_ctx[die] = (clang::DeclContext*)namespace_decl;
+ return namespace_decl;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ clang::DeclContext *decl_ctx;
+ decl_ctx = GetClangDeclContextForDIEOffset (die->GetAttributeValueAsUnsigned(this, cu, DW_AT_specification, DW_INVALID_OFFSET));
+ if (decl_ctx)
+ return decl_ctx;
+
+ decl_ctx = GetClangDeclContextForDIEOffset (die->GetAttributeValueAsUnsigned(this, cu, DW_AT_abstract_origin, DW_INVALID_OFFSET));
+ if (decl_ctx)
+ return decl_ctx;
+
+ die = die->GetParent();
+ }
+ return NULL;
+}
+
+TypeSP
+SymbolFileDWARF::ParseType(const SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool &type_is_new)
+{
+ TypeSP type_sp;
+
+ uint32_t accessibility = clang::AS_none;
+ if (die != NULL)
+ {
+ dw_tag_t tag = die->Tag();
+ if (die->GetUserData() == NULL)
+ {
+ type_is_new = true;
+
+ bool is_forward_declaration = false;
+ DWARFDebugInfoEntry::Attributes attributes;
+ const char *type_name_cstr = NULL;
+ ConstString type_name_dbstr;
+ Type::EncodingUIDType encoding_uid_type = Type::eIsTypeWithUID;
+ void *clang_type = NULL;
+
+ TypeList* type_list = m_obj_file->GetModule()->GetTypeList();
+ dw_attr_t attr;
+
+ switch (tag)
+ {
+ case DW_TAG_base_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_typedef:
+ case DW_TAG_const_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_volatile_type:
+ {
+ //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag));
+ // Set a bit that lets us know that we are currently parsing this
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED);
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ Declaration decl;
+ uint32_t encoding = 0;
+ size_t byte_size = 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());
+ type_name_dbstr.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;
+ }
+ }
+ }
+ }
+
+ switch (tag)
+ {
+ default:
+ case DW_TAG_base_type:
+ clang_type = type_list->GetClangASTContext().GetBuiltinTypeForDWARFEncodingAndBitSize (type_name_cstr, encoding, byte_size * 8);
+ break;
+
+ case DW_TAG_pointer_type:
+ // The encoding_uid will be embedded into the
+ // Type object and will be looked up when the Type::GetOpaqueClangQualType()
+ encoding_uid_type = Type::ePointerToTypeWithUID;
+ break;
+
+ case DW_TAG_reference_type:
+ // The encoding_uid will be embedded into the
+ // Type object and will be looked up when the Type::GetOpaqueClangQualType()
+ encoding_uid_type = Type::eLValueReferenceToTypeWithUID;
+ break;
+
+ case DW_TAG_typedef:
+ // The encoding_uid will be embedded into the
+ // Type object and will be looked up when the Type::GetOpaqueClangQualType()
+ encoding_uid_type = Type::eTypedefToTypeWithUID;
+ break;
+
+ case DW_TAG_const_type:
+ // The encoding_uid will be embedded into the
+ // Type object and will be looked up when the Type::GetOpaqueClangQualType()
+ encoding_uid_type = Type::eIsConstTypeWithUID; //ClangASTContext::AddConstModifier (clang_type);
+ break;
+
+ case DW_TAG_restrict_type:
+ // The encoding_uid will be embedded into the
+ // Type object and will be looked up when the Type::GetOpaqueClangQualType()
+ encoding_uid_type = Type::eIsRestrictTypeWithUID; //ClangASTContext::AddRestrictModifier (clang_type);
+ break;
+
+ case DW_TAG_volatile_type:
+ // The encoding_uid will be embedded into the
+ // Type object and will be looked up when the Type::GetOpaqueClangQualType()
+ encoding_uid_type = Type::eIsVolatileTypeWithUID; //ClangASTContext::AddVolatileModifier (clang_type);
+ break;
+ }
+
+ type_sp.reset( new Type(die->GetOffset(), this, type_name_dbstr, byte_size, NULL, encoding_uid, encoding_uid_type, &decl, clang_type));
+
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(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:
+ {
+ //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag));
+ // Set a bit that lets us know that we are currently parsing this
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED);
+
+ size_t byte_size = 0;
+ //bool struct_is_class = false;
+ Declaration decl;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, 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_dbstr.SetCString(type_name_cstr);
+ break;
+ case DW_AT_byte_size: byte_size = form_value.Unsigned(); break;
+ case DW_AT_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break; break;
+ case DW_AT_declaration: is_forward_declaration = form_value.Unsigned() != 0; 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;
+ }
+ }
+ }
+ }
+
+ int tag_decl_kind = -1;
+ int default_accessibility = clang::AS_none;
+ if (tag == DW_TAG_structure_type)
+ {
+ tag_decl_kind = clang::TTK_Struct;
+ default_accessibility = clang::AS_public;
+ }
+ else if (tag == DW_TAG_union_type)
+ {
+ tag_decl_kind = clang::TTK_Union;
+ default_accessibility = clang::AS_public;
+ }
+ else if (tag == DW_TAG_class_type)
+ {
+ tag_decl_kind = clang::TTK_Class;
+ default_accessibility = clang::AS_private;
+ }
+
+ assert (tag_decl_kind != -1);
+ clang_type = type_list->GetClangASTContext().CreateRecordType (type_name_cstr, tag_decl_kind, GetClangDeclContextForDIE (dwarf_cu, die));
+
+ m_die_to_decl_ctx[die] = ClangASTContext::GetDeclContextForType (clang_type);
+ type_sp.reset( new Type(die->GetOffset(), this, type_name_dbstr, byte_size, NULL, LLDB_INVALID_UID, Type::eIsTypeWithUID, &decl, clang_type));
+
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get());
+
+// assert(type_sp.get());
+// if (accessibility)
+// type_sp->SetAccess(accessibility);
+//
+ type_list->GetClangASTContext().StartTagDeclarationDefinition (clang_type);
+ if (die->HasChildren())
+ {
+ std::vector<clang::CXXBaseSpecifier *> base_classes;
+ std::vector<int> member_accessibilities;
+ bool is_a_class = false;
+ ParseChildMembers(sc, type_sp, dwarf_cu, die, base_classes, member_accessibilities, default_accessibility, is_a_class);
+ // 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 (is_a_class && tag_decl_kind != clang::TTK_Class)
+ type_list->GetClangASTContext().SetTagTypeKind (clang_type, 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.
+ type_list->GetClangASTContext().SetDefaultAccessForRecordFields (clang_type, clang::AS_private, member_accessibilities.data(), member_accessibilities.size());
+ }
+
+ if (!base_classes.empty())
+ {
+ type_list->GetClangASTContext().SetBaseClassesForClassType (clang_type, base_classes.data(), base_classes.size());
+ }
+ }
+ type_list->GetClangASTContext().CompleteTagDeclarationDefinition (clang_type);
+ }
+ break;
+
+ case DW_TAG_enumeration_type:
+ {
+ //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag));
+ // Set a bit that lets us know that we are currently parsing this
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED);
+
+ size_t byte_size = 0;
+ lldb::user_id_t encoding_uid = DW_INVALID_OFFSET;
+ Declaration decl;
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, 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_dbstr.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: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break;
+ case DW_AT_declaration: is_forward_declaration = form_value.Unsigned() != 0; 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;
+ }
+ }
+ }
+
+ clang_type = type_list->GetClangASTContext().CreateEnumerationType(decl, type_name_cstr);
+ m_die_to_decl_ctx[die] = ClangASTContext::GetDeclContextForType (clang_type);
+ type_sp.reset( new Type(die->GetOffset(), this, type_name_dbstr, byte_size, NULL, encoding_uid, Type::eIsTypeWithUID, &decl, clang_type));
+
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get());
+
+ if (die->HasChildren())
+ {
+ type_list->GetClangASTContext().StartTagDeclarationDefinition (clang_type);
+ void *enumerator_qual_type = type_list->GetClangASTContext().GetBuiltinTypeForDWARFEncodingAndBitSize (NULL, DW_ATE_signed, byte_size * 8);
+ ParseChildEnumerators(sc, type_sp, enumerator_qual_type, byte_size, dwarf_cu, die);
+ type_list->GetClangASTContext().CompleteTagDeclarationDefinition (clang_type);
+ }
+ }
+ }
+ break;
+
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ {
+ //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag));
+ // Set a bit that lets us know that we are currently parsing this
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED);
+
+ const char *mangled = NULL;
+ dw_offset_t type_die_offset = DW_INVALID_OFFSET;
+ Declaration decl;
+ bool isVariadic = false;
+ bool is_inline = false;
+ unsigned type_quals = 0;
+ clang::FunctionDecl::StorageClass storage = clang::FunctionDecl::None;//, Extern, Static, PrivateExtern
+
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, 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_dbstr.SetCString(type_name_cstr);
+ break;
+
+ case DW_AT_MIPS_linkage_name: 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 = DwarfToClangAccessibility(form_value.Unsigned()); break;
+ case DW_AT_declaration: is_forward_declaration = form_value.Unsigned() != 0; break;
+ case DW_AT_external:
+ if (form_value.Unsigned())
+ {
+ if (storage == clang::FunctionDecl::None)
+ storage = clang::FunctionDecl::Extern;
+ else
+ storage = clang::FunctionDecl::PrivateExtern;
+ }
+ break;
+ case DW_AT_inline:
+ is_inline = form_value.Unsigned() != 0;
+ break;
+
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_address_class:
+ case DW_AT_artificial:
+ case DW_AT_calling_convention:
+ case DW_AT_data_location:
+ case DW_AT_elemental:
+ case DW_AT_entry_pc:
+ case DW_AT_explicit:
+ case DW_AT_frame_base:
+ case DW_AT_high_pc:
+ case DW_AT_low_pc:
+ case DW_AT_object_pointer:
+ 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_specification:
+ case DW_AT_start_scope:
+ case DW_AT_static_link:
+ case DW_AT_trampoline:
+ case DW_AT_visibility:
+ case DW_AT_virtuality:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_abstract_origin:
+ case DW_AT_description:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ void *return_clang_type = NULL;
+ Type *func_type = ResolveTypeUID(type_die_offset);
+ if (func_type)
+ return_clang_type = func_type->GetOpaqueClangQualType();
+ else
+ return_clang_type = type_list->GetClangASTContext().GetVoidBuiltInType();
+
+ std::vector<void *> function_param_types;
+ std::vector<clang::ParmVarDecl*> function_param_decls;
+
+ // Parse the function children for the parameters
+ ParseChildParameters(sc, type_sp, dwarf_cu, die, type_list, function_param_types, function_param_decls);
+
+ clang_type = type_list->GetClangASTContext().CreateFunctionType (return_clang_type, &function_param_types[0], function_param_types.size(), isVariadic, type_quals);
+ if (type_name_cstr)
+ {
+ clang::FunctionDecl *function_decl = type_list->GetClangASTContext().CreateFunctionDeclaration (type_name_cstr, clang_type, storage, is_inline);
+ // Add the decl to our DIE to decl context map
+ assert (function_decl);
+ m_die_to_decl_ctx[die] = function_decl;
+ if (!function_param_decls.empty())
+ type_list->GetClangASTContext().SetFunctionParameters (function_decl, function_param_decls.data(), function_param_decls.size());
+ }
+ type_sp.reset( new Type(die->GetOffset(), this, type_name_dbstr, 0, NULL, LLDB_INVALID_UID, Type::eIsTypeWithUID, &decl, clang_type));
+
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get());
+ assert(type_sp.get());
+ }
+ }
+ break;
+
+ case DW_TAG_array_type:
+ {
+ //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag));
+ // Set a bit that lets us know that we are currently parsing this
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED);
+
+ size_t byte_size = 0;
+ lldb::user_id_t type_die_offset = DW_INVALID_OFFSET;
+ Declaration decl;
+ int64_t first_index = 0;
+ uint32_t byte_stride = 0;
+ uint32_t bit_stride = 0;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, 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_dbstr.SetCString(type_name_cstr);
+ break;
+
+ case DW_AT_type: type_die_offset = form_value.Reference(dwarf_cu); break;
+ case DW_AT_byte_size: 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_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break;
+ case DW_AT_declaration: is_forward_declaration = form_value.Unsigned() != 0; 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;
+ }
+ }
+ }
+
+ 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();
+ void *array_element_type = element_type->GetOpaqueClangQualType();
+ 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 = type_list->GetClangASTContext().CreateArrayType (array_element_type, num_elements, num_elements * array_element_bit_stride);
+ array_element_type = clang_type;
+ array_element_bit_stride = array_element_bit_stride * num_elements;
+ }
+ ConstString empty_name;
+ type_sp.reset( new Type(die->GetOffset(), this, empty_name, array_element_bit_stride / 8, NULL, LLDB_INVALID_UID, Type::eIsTypeWithUID, &decl, clang_type));
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get());
+ }
+ }
+ }
+ break;
+
+ default:
+ 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->GetBlocks(true).GetBlockByID(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);
+ }
+
+// if (udt_sp.get())
+// {
+// if (is_forward_declaration)
+// udt_sp->GetFlags().Set(UserDefType::flagIsForwardDefinition);
+// type_sp->SetUserDefinedType(udt_sp);
+// }
+
+ if (type_sp.unique())
+ {
+ // We are ready to put this type into the uniqued list up at the module level
+ TypeSP uniqued_type_sp(m_obj_file->GetModule()->GetTypeList()->InsertUnique(type_sp));
+
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(uniqued_type_sp.get());
+
+ type_sp = uniqued_type_sp;
+ }
+ }
+ }
+ else
+ {
+ switch (tag)
+ {
+ case DW_TAG_base_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_typedef:
+ case DW_TAG_const_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_array_type:
+ {
+ Type *existing_type = (Type*)die->GetUserData();
+ if (existing_type != DIE_IS_BEING_PARSED)
+ {
+ type_sp = m_obj_file->GetModule()->GetTypeList()->FindType(existing_type->GetID());
+ }
+ }
+ break;
+ default:
+ //assert(!"invalid type tag...");
+ break;
+ }
+ }
+ }
+ return type_sp;
+}
+
+size_t
+SymbolFileDWARF::ParseTypes (const SymbolContext& sc, const 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(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 = GetDWARFCompileUnitForUID(sc.comp_unit->GetID());
+ 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, Block::RootID, dwarf_cu, function_die, LLDB_INVALID_ADDRESS, false, true);
+ }
+ }
+
+ 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 = GetDWARFCompileUnitForUID(sc.comp_unit->GetID());
+ 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)
+ {
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID());
+
+ if (dwarf_cu == NULL)
+ return 0;
+
+ if (sc.function)
+ {
+ const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(sc.function->GetID());
+ return ParseVariables(sc, dwarf_cu, function_die->GetFirstChild(), true, true);
+ }
+ else if (sc.comp_unit)
+ {
+ 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);
+
+ // 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 ();
+
+ const size_t num_globals = dwarf_cu->GetNumGlobals();
+ for (size_t idx=0; idx<num_globals; ++idx)
+ {
+ VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, dwarf_cu->GetGlobalDIEAtIndex (idx)));
+ if (var_sp)
+ {
+ variables->AddVariable(var_sp);
+ ++vars_added;
+ }
+ }
+ }
+ return vars_added;
+ }
+ }
+ return 0;
+}
+
+
+VariableSP
+SymbolFileDWARF::ParseVariableDIE
+(
+ const SymbolContext& sc,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die
+)
+{
+
+ VariableSP var_sp;
+
+ const dw_tag_t tag = die->Tag();
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes);
+ if (num_attributes > 0)
+ {
+ const char *name = NULL;
+ Declaration decl;
+ uint32_t i;
+ TypeSP type_sp;
+ Type *var_type = NULL;
+ DWARFExpression location;
+ bool is_external = false;
+ bool is_artificial = false;
+ uint32_t accessibility = clang::AS_none;
+
+ 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_type: var_type = GetUniquedTypeForDIEOffset(form_value.Reference(dwarf_cu), type_sp, 0, 0, false); break;
+ case DW_AT_external: is_external = form_value.Unsigned() != 0; break;
+ case DW_AT_location:
+ {
+ 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.SetOpcodeData(get_debug_info_data(), block_offset, block_length, NULL);
+ }
+ 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)
+ {
+ Address base_address(dwarf_cu->GetBaseAddress(), m_obj_file->GetSectionList());
+ location.SetOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length, &base_address);
+ }
+ }
+ }
+ break;
+
+ case DW_AT_artificial: is_artificial = form_value.Unsigned() != 0; break;
+ case DW_AT_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break;
+ case DW_AT_const_value:
+ 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;
+ }
+ }
+ }
+
+ if (location.IsValid())
+ {
+ assert(var_type != DIE_IS_BEING_PARSED);
+
+ ConstString var_name(name);
+
+ ValueType scope = eValueTypeInvalid;
+
+ const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die);
+ dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
+
+ if (tag == DW_TAG_formal_parameter)
+ scope = eValueTypeVariableArgument;
+ else if (is_external || parent_tag == DW_TAG_compile_unit)
+ scope = eValueTypeVariableGlobal;
+ else
+ scope = eValueTypeVariableLocal;
+
+ SymbolContextScope * symbol_context_scope = NULL;
+ if (parent_tag == DW_TAG_compile_unit)
+ {
+ symbol_context_scope = sc.comp_unit;
+ }
+ else if (sc.function != NULL)
+ {
+ symbol_context_scope = sc.function->GetBlocks(true).GetBlockByID(sc_parent_die->GetOffset());
+ if (symbol_context_scope == NULL)
+ symbol_context_scope = sc.function;
+ }
+
+ assert(symbol_context_scope != NULL);
+ var_sp.reset (new Variable(die->GetOffset(),
+ var_name,
+ var_type,
+ scope,
+ symbol_context_scope,
+ &decl,
+ location,
+ is_external,
+ is_artificial));
+ const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(var_sp.get());
+ }
+ }
+ return var_sp;
+}
+
+size_t
+SymbolFileDWARF::ParseVariables
+(
+ const SymbolContext& sc,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *orig_die,
+ bool parse_siblings,
+ bool parse_children,
+ VariableList* cc_variable_list
+)
+{
+ if (orig_die == NULL)
+ return 0;
+
+ size_t vars_added = 0;
+ const DWARFDebugInfoEntry *die = orig_die;
+ const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(orig_die);
+ dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
+ VariableListSP variables;
+ switch (parent_tag)
+ {
+ case DW_TAG_compile_unit:
+ if (sc.comp_unit != NULL)
+ {
+ variables = sc.comp_unit->GetVariableList(false);
+ if (variables.get() == NULL)
+ {
+ variables.reset(new VariableList());
+ sc.comp_unit->SetVariableList(variables);
+ }
+ }
+ else
+ {
+ assert(!"Parent DIE was a compile unit, yet we don't have a valid compile unit in the symbol context...");
+ vars_added = 0;
+ }
+ 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
+ variables = sc.function->GetBlocks(true).GetVariableList(sc_parent_die->GetOffset(), false, false);
+ if (variables.get() == NULL)
+ {
+ variables.reset(new VariableList());
+ sc.function->GetBlocks(true).SetVariableList(sc_parent_die->GetOffset(), variables);
+ }
+ }
+ else
+ {
+ assert(!"Parent DIE was a function or block, yet we don't have a function in the symbol context...");
+ vars_added = 0;
+ }
+ break;
+
+ default:
+ assert(!"Didn't find appropriate parent DIE for variable list...");
+ break;
+ }
+
+ // We need to have a variable list at this point that we can add variables to
+ assert(variables.get());
+
+ while (die != NULL)
+ {
+ dw_tag_t tag = die->Tag();
+
+ // Check to see if we have already parsed this variable or constant?
+ if (die->GetUserData() == NULL)
+ {
+ // 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))
+ {
+ VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, die));
+ if (var_sp)
+ {
+ variables->AddVariable(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, die->GetFirstChild(), true, true);
+ //vars_added += ParseVariables(sc, dwarf_cu, die->GetFirstChild(), parse_siblings, parse_children);
+ }
+
+ if (parse_siblings)
+ die = die->GetSibling();
+ else
+ die = NULL;
+ }
+
+ if (cc_variable_list)
+ {
+ cc_variable_list->AddVariables(variables.get());
+ }
+
+ return vars_added;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+SymbolFileDWARF::GetPluginName()
+{
+ return "SymbolFileDWARF";
+}
+
+const char *
+SymbolFileDWARF::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolFileDWARF::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+SymbolFileDWARF::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+SymbolFileDWARF::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+SymbolFileDWARF::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
new file mode 100644
index 00000000000..95545a4844e
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -0,0 +1,331 @@
+//===-- 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 liblldb_SymbolFileDWARF_h_
+#define liblldb_SymbolFileDWARF_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <memory>
+#include <map>
+#include <vector>
+
+// Other libraries and framework includes
+#include "llvm/ADT/DenseMap.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+// Project includes
+#include "DWARFDefines.h"
+
+
+//----------------------------------------------------------------------
+// Forward Declarations for this DWARF plugin
+//----------------------------------------------------------------------
+class DWARFAbbreviationDeclaration;
+class DWARFAbbreviationDeclarationSet;
+class DWARFCompileUnit;
+class DWARFDebugAbbrev;
+class DWARFDebugAranges;
+class DWARFDebugInfo;
+class DWARFDebugInfoEntry;
+class DWARFDebugLine;
+class DWARFDebugPubnames;
+class DWARFDebugRanges;
+class DWARFDIECollection;
+class DWARFFormValue;
+
+class SymbolFileDWARF : public lldb_private::SymbolFile
+{
+public:
+ friend class SymbolFileDWARFDebugMap;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ 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 GetAbilities ();
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ virtual uint32_t GetNumCompileUnits();
+ virtual lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index);
+
+ 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* GetClangDeclContextForTypeUID (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, 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, bool append, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindFunctions(const lldb_private::RegularExpression& regex, bool append, lldb_private::SymbolContextList& sc_list);
+// virtual uint32_t FindTypes(const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, bool append, uint32_t max_matches, lldb::Type::Encoding encoding, lldb::user_id_t udt_uid, lldb_private::TypeList& types);
+// virtual uint32_t FindTypes(const lldb_private::SymbolContext& sc, const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb::Type::Encoding encoding, lldb::user_id_t udt_uid, lldb_private::TypeList& types);
+
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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);
+
+ // 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_macinfo_data();
+ const lldb_private::DataExtractor& get_debug_pubnames_data();
+ const lldb_private::DataExtractor& get_debug_pubtypes_data();
+ const lldb_private::DataExtractor& get_debug_ranges_data();
+ const lldb_private::DataExtractor& get_debug_str_data();
+
+ DWARFDebugAbbrev* DebugAbbrev();
+ const DWARFDebugAbbrev* DebugAbbrev() const;
+
+ DWARFDebugAranges* DebugAranges();
+ const DWARFDebugAranges*DebugAranges() const;
+
+ DWARFDebugInfo* DebugInfo();
+ const DWARFDebugInfo* DebugInfo() const;
+
+// These shouldn't be used unless we want to dump the DWARF line tables.
+// DWARFDebugLine* DebugLine();
+// const DWARFDebugLine* DebugLine() const;
+
+// DWARFDebugPubnames* DebugPubnames();
+// const DWARFDebugPubnames* DebugPubnames() const;
+//
+// DWARFDebugPubnames* DebugPubBaseTypes();
+// const DWARFDebugPubnames* DebugPubBaseTypes() const;
+//
+// DWARFDebugPubnames* DebugPubtypes();
+// const DWARFDebugPubnames* DebugPubtypes() const;
+
+ DWARFDebugRanges* DebugRanges();
+ const DWARFDebugRanges* DebugRanges() const;
+
+ const lldb_private::DataExtractor&
+ GetCachedSectionData (uint32_t got_flag, const lldb_private::ConstString &section_name, lldb_private::DataExtractor &data);
+
+ static bool SupportedVersion(uint16_t version);
+
+ clang::DeclContext *
+ GetClangDeclContextForDIE (const DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die);
+
+ clang::DeclContext *
+ GetClangDeclContextForDIEOffset (dw_offset_t die_offset);
+
+ lldb_private::Flags&
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const lldb_private::Flags&
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+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),
+ // True if this is a .o file used when resolving a N_OSO entry with
+ // debug maps.
+ flagsDWARFIsOSOForDebugMap = (1 << 16)
+ };
+
+ DISALLOW_COPY_AND_ASSIGN (SymbolFileDWARF);
+ bool ParseCompileUnit(DWARFCompileUnit* cu, lldb::CompUnitSP& compile_unit_sp);
+ DWARFCompileUnit* GetDWARFCompileUnitForUID(lldb::user_id_t cu_uid);
+ DWARFCompileUnit* GetNextUnparsedDWARFCompileUnit(DWARFCompileUnit* prev_cu);
+ lldb_private::CompileUnit* GetCompUnitForDWARFCompUnit(DWARFCompileUnit* cu, uint32_t cu_idx = UINT_MAX);
+ bool GetFunction (DWARFCompileUnit* cu, const DWARFDebugInfoEntry* func_die, lldb_private::SymbolContext& sc);
+ lldb_private::Function * ParseCompileUnitFunction (const lldb_private::SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die);
+ size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc,
+ lldb::user_id_t parentBlockID,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ lldb::addr_t subprogram_low_pc,
+ bool parse_siblings,
+ bool parse_children);
+ size_t ParseTypes (const lldb_private::SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool parse_siblings, bool parse_children);
+ lldb::TypeSP ParseType (const lldb_private::SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool &type_is_new);
+
+ lldb::VariableSP ParseVariableDIE(
+ const lldb_private::SymbolContext& sc,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die);
+
+ size_t ParseVariables(
+ const lldb_private::SymbolContext& sc,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ bool parse_siblings,
+ bool parse_children,
+ lldb_private::VariableList* cc_variable_list = NULL);
+
+ size_t ParseChildMembers(
+ const lldb_private::SymbolContext& sc,
+ lldb::TypeSP& type_sp,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ std::vector<clang::CXXBaseSpecifier *>& base_classes,
+ std::vector<int>& member_accessibilities,
+ int &default_accessibility,
+ bool &is_a_class);
+
+ size_t ParseChildParameters(
+ const lldb_private::SymbolContext& sc,
+ lldb::TypeSP& type_sp,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ lldb_private::TypeList* type_list,
+ std::vector<void *>& function_args,
+ std::vector<clang::ParmVarDecl*>& function_param_decls);
+
+ size_t ParseChildEnumerators(
+ const lldb_private::SymbolContext& sc,
+ lldb::TypeSP& type_sp,
+ void *enumerator_qual_type,
+ uint32_t enumerator_byte_size,
+ const DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *enum_die);
+
+ void ParseChildArrayInfo(
+ const lldb_private::SymbolContext& sc,
+ const 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);
+
+ lldb_private::Type* GetUniquedTypeForDIEOffset(dw_offset_t type_die_offset, lldb::TypeSP& owning_type_sp, int32_t child_type, uint32_t idx, bool safe);
+ lldb::TypeSP GetTypeForDIE(DWARFCompileUnit *cu, const DWARFDebugInfoEntry* die, lldb::TypeSP& owning_type_sp, int32_t child_type, uint32_t idx);
+// uint32_t FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types);
+
+ void Index();
+
+ 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_macinfo;
+ lldb_private::DataExtractor m_data_debug_pubnames;
+ lldb_private::DataExtractor m_data_debug_pubtypes;
+ lldb_private::DataExtractor m_data_debug_ranges;
+ lldb_private::DataExtractor m_data_debug_str;
+
+ // The auto_ptr items below are generated on demand if and when someone accesses
+ // them through a non const version of this class.
+ std::auto_ptr<DWARFDebugAbbrev> m_abbr;
+ std::auto_ptr<DWARFDebugAranges> m_aranges;
+ std::auto_ptr<DWARFDebugInfo> m_info;
+ std::auto_ptr<DWARFDebugLine> m_line;
+ lldb_private::UniqueCStringMap<dw_offset_t> m_name_to_function_die; // All concrete functions
+ lldb_private::UniqueCStringMap<dw_offset_t> m_name_to_inlined_die; // All inlined functions
+ lldb_private::UniqueCStringMap<dw_offset_t> m_name_to_global_die; // Global and static variables
+ lldb_private::UniqueCStringMap<dw_offset_t> m_name_to_type_die; // All type DIE offsets
+ bool m_indexed;
+
+// std::auto_ptr<DWARFDebugPubnames> m_pubnames;
+// std::auto_ptr<DWARFDebugPubnames> m_pubbasetypes; // Just like m_pubtypes, but for DW_TAG_base_type DIEs
+// std::auto_ptr<DWARFDebugPubnames> m_pubtypes;
+ std::auto_ptr<DWARFDebugRanges> m_ranges;
+
+ typedef llvm::DenseMap<const DWARFDebugInfoEntry *, clang::DeclContext *> DIEToDeclContextMap;
+ DIEToDeclContextMap m_die_to_decl_ctx;
+
+// TypeFixupColl m_type_fixups;
+// std::vector<Type*> m_indirect_fixups;
+
+//#define LLDB_SYMBOL_FILE_DWARF_SHRINK_TEST 1
+#if defined(LLDB_SYMBOL_FILE_DWARF_SHRINK_TEST)
+
+ typedef std::map<FileSpec, DWARFDIECollection> FSToDIES;
+ void ShrinkDSYM(CompileUnit *dc_cu, DWARFCompileUnit *dw_cu, const FileSpec& cu_fspec, const FileSpec& base_types_cu_fspec, FSToDIES& fs_to_dies, const DWARFDebugInfoEntry *die);
+#endif
+};
+
+#endif // liblldb_SymbolFileDWARF_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
new file mode 100644
index 00000000000..7bf968dd9ce
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -0,0 +1,873 @@
+//===-- 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 "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+
+#include "SymbolFileDWARF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+SymbolFileDWARFDebugMap::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolFileDWARFDebugMap::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+SymbolFileDWARFDebugMap::GetPluginNameStatic()
+{
+ return "symbol-file.dwarf2-debugmap";
+}
+
+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()
+{
+}
+
+
+SymbolFileDWARFDebugMap::~SymbolFileDWARFDebugMap()
+{
+}
+
+void
+SymbolFileDWARFDebugMap::InitOSO ()
+{
+ if (m_flags.test(kHaveInitializedOSOs))
+ return;
+
+ m_flags.set(kHaveInitializedOSOs);
+ // 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)
+ {
+ //StreamFile s(0, 4, eByteOrderHost, stdout);
+ std::vector<uint32_t> oso_indexes;
+ const uint32_t oso_index_count = symtab->AppendSymbolIndexesWithType(eSymbolTypeObjectFile, oso_indexes);
+
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeFunction, m_func_indexes);
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeGlobal, m_glob_indexes);
+
+ symtab->SortSymbolIndexesByValue(m_func_indexes, true);
+ symtab->SortSymbolIndexesByValue(m_glob_indexes, true);
+
+ if (oso_index_count > 0)
+ {
+ m_compile_unit_infos.resize(oso_index_count);
+// s.Printf("%s N_OSO symbols:\n", __PRETTY_FUNCTION__);
+// symtab->Dump(&s, oso_indexes);
+
+ for (uint32_t i=0; i<oso_index_count; ++i)
+ {
+ m_compile_unit_infos[i].so_symbol = symtab->SymbolAtIndex(oso_indexes[i] - 1);
+ if (m_compile_unit_infos[i].so_symbol->GetSiblingIndex() == 0)
+ m_compile_unit_infos[i].so_symbol = symtab->SymbolAtIndex(oso_indexes[i] - 2);
+ m_compile_unit_infos[i].oso_symbol = symtab->SymbolAtIndex(oso_indexes[i]);
+ }
+ }
+ }
+}
+
+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_module_sp.get() == NULL)
+ {
+ Symbol *oso_symbol = comp_unit_info->oso_symbol;
+ if (oso_symbol)
+ {
+ FileSpec oso_file_spec(oso_symbol->GetMangled().GetName().AsCString());
+
+ ModuleList::GetSharedModule (oso_file_spec,
+ m_obj_file->GetModule()->GetArchitecture(),
+ NULL, // UUID pointer
+ NULL, // object name
+ 0, // object offset
+ comp_unit_info->oso_module_sp,
+ NULL,
+ NULL);
+ //comp_unit_info->oso_module_sp.reset(new Module (oso_file_spec, m_obj_file->GetModule()->GetArchitecture()));
+ }
+ }
+ return comp_unit_info->oso_module_sp.get();
+}
+
+
+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)
+ {
+
+ if (m_compile_unit_infos[oso_idx].so_symbol == NULL)
+ return false;
+
+ std::string so_path (m_compile_unit_infos[oso_idx].so_symbol->GetMangled().GetName().AsCString());
+ if (m_compile_unit_infos[oso_idx].so_symbol[1].GetType() == eSymbolTypeSourceFile)
+ so_path += m_compile_unit_infos[oso_idx].so_symbol[1].GetMangled().GetName().AsCString();
+ m_compile_unit_infos[oso_idx].so_file.SetFile(so_path.c_str());
+ }
+ 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;
+}
+
+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::GetSymbolFileByCompUnitInfo (CompileUnitInfo *comp_unit_info)
+{
+ if (comp_unit_info->oso_symbol_vendor == NULL)
+ {
+ ObjectFile *oso_objfile = GetObjectFileByCompUnitInfo (comp_unit_info);
+
+ if (oso_objfile)
+ {
+ comp_unit_info->oso_symbol_vendor = oso_objfile->GetModule()->GetSymbolVendor();
+// SymbolFileDWARF *oso_dwarf = new SymbolFileDWARF(oso_objfile);
+// comp_unit_info->oso_dwarf_sp.reset (oso_dwarf);
+ if (comp_unit_info->oso_symbol_vendor)
+ {
+ // Set a bit that lets this DWARF file know that it is being
+ // used along with a debug map and that it will have the
+ // remapped sections that we do below.
+ ((SymbolFileDWARF *)comp_unit_info->oso_symbol_vendor->GetSymbolFile())->GetFlags().Set(SymbolFileDWARF::flagsDWARFIsOSOForDebugMap);
+ comp_unit_info->debug_map_sections_sp.reset(new SectionList);
+
+ Symtab *exe_symtab = m_obj_file->GetSymtab();
+ Module *oso_module = oso_objfile->GetModule();
+ Symtab *oso_symtab = oso_objfile->GetSymtab();
+//#define DEBUG_OSO_DMAP // Do not check in with this defined...
+#if defined(DEBUG_OSO_DMAP)
+ StreamFile s(stdout);
+ s << "OSO symtab:\n";
+ oso_symtab->Dump(&s, NULL);
+ s << "OSO sections before:\n";
+ oso_objfile->GetSectionList()->Dump(&s, NULL, true);
+#endif
+
+ ///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.
+ uint32_t oso_start_idx = comp_unit_info->oso_symbol->GetID() + 1;
+ const uint32_t oso_end_idx = comp_unit_info->so_symbol->GetSiblingIndex();
+ uint32_t sect_id = 0x10000;
+ for (uint32_t idx = oso_start_idx; idx < oso_end_idx; ++idx)
+ {
+ Symbol *exe_symbol = exe_symtab->SymbolAtIndex(idx);
+ if (exe_symbol)
+ {
+ switch (exe_symbol->GetType())
+ {
+ case eSymbolTypeFunction:
+ {
+ // 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(), eSymbolTypeCode);
+ if (oso_fun_symbol)
+ {
+ // If we found the symbol, then we
+ Section* exe_fun_section = const_cast<Section *>(exe_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection());
+ Section* oso_fun_section = const_cast<Section *>(oso_fun_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection());
+ if (oso_fun_section)
+ {
+ // Now we create a section that we will add as a child of the
+ // section in which the .o symbol (the N_FUN) exists.
+
+ // We use the exe_symbol size because the one in the .o file
+ // will just be a symbol with no size, and the exe_symbol
+ // size will reflect any size changes (ppc has been known to
+ // shrink function sizes when it gets rid of jump islands that
+ // aren't needed anymore).
+ SectionSP oso_fun_section_sp (new Section (const_cast<Section *>(oso_fun_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()),
+ oso_module, // Module (the .o file)
+ sect_id++, // Section ID starts at 0x10000 and increments so the section IDs don't overlap with the standard mach IDs
+ exe_symbol->GetMangled().GetName(), // Name the section the same as the symbol for which is was generated!
+ eSectionTypeDebug,
+ oso_fun_symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(), // File VM address offset in the current section
+ exe_symbol->GetByteSize(), // File size (we need the size from the executable)
+ 0, 0, 0));
+
+ oso_fun_section_sp->SetLinkedLocation (exe_fun_section,
+ exe_symbol->GetValue().GetFileAddress() - exe_fun_section->GetFileAddress());
+ oso_fun_section->GetChildren().AddSection(oso_fun_section_sp);
+ comp_unit_info->debug_map_sections_sp->AddSection(oso_fun_section_sp);
+ }
+ }
+ }
+ break;
+
+ case eSymbolTypeGlobal:
+ case eSymbolTypeStatic:
+ {
+ // 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.
+
+#if 0
+ // First we find the non-stab entry that corresponds to the N_GSYM in the executable
+ Symbol *exe_gsym_symbol = exe_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeData);
+#else
+ // The mach-o object file parser already matches up the N_GSYM with with the non-stab
+ // entry, so we shouldn't have to do that. If this ever changes, enable the code above
+ // in the "#if 0" block. STSYM's always match the symbol as found below.
+ Symbol *exe_gsym_symbol = exe_symbol;
+#endif
+ // 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(), eSymbolTypeData);
+ if (exe_gsym_symbol && oso_gsym_symbol)
+ {
+ // If we found the symbol, then we
+ Section* exe_gsym_section = const_cast<Section *>(exe_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection());
+ Section* oso_gsym_section = const_cast<Section *>(oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection());
+ if (oso_gsym_section)
+ {
+ SectionSP oso_gsym_section_sp (new Section (const_cast<Section *>(oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()),
+ oso_module, // Module (the .o file)
+ sect_id++, // Section ID starts at 0x10000 and increments so the section IDs don't overlap with the standard mach IDs
+ exe_symbol->GetMangled().GetName(), // Name the section the same as the symbol for which is was generated!
+ eSectionTypeDebug,
+ oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(), // File VM address offset in the current section
+ 1, // We don't know the size of the global, just do the main address for now.
+ 0, 0, 0));
+
+ oso_gsym_section_sp->SetLinkedLocation (exe_gsym_section,
+ exe_gsym_symbol->GetValue().GetFileAddress() - exe_gsym_section->GetFileAddress());
+ oso_gsym_section->GetChildren().AddSection(oso_gsym_section_sp);
+ comp_unit_info->debug_map_sections_sp->AddSection(oso_gsym_section_sp);
+ }
+ }
+ }
+ break;
+
+// case eSymbolTypeStatic:
+// {
+// // For each N_STSYM 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.
+//
+//
+// Symbol *exe_stsym_symbol = exe_symbol;
+// // First we find the non-stab entry that corresponds to the N_STSYM in the .o file
+// Symbol *oso_stsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeData);
+// if (exe_stsym_symbol && oso_stsym_symbol)
+// {
+// // If we found the symbol, then we
+// Section* exe_stsym_section = const_cast<Section *>(exe_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection());
+// Section* oso_stsym_section = const_cast<Section *>(oso_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection());
+// if (oso_stsym_section)
+// {
+// // The load address of the symbol will use the section in the
+// // executable that contains the debug map that corresponds to
+// // the N_FUN symbol. We set the offset to reflect the offset
+// // into that section since we are creating a new section.
+// AddressRange stsym_load_range(exe_stsym_section, exe_stsym_symbol->GetValue().GetFileAddress() - exe_stsym_section->GetFileAddress(), 1);
+// // We need the symbol's section offset address from the .o file, but
+// // we need a non-zero size.
+// AddressRange stsym_file_range(exe_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection(), exe_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(), 1);
+//
+// // Now we create a section that we will add as a child of the
+// // section in which the .o symbol (the N_FUN) exists.
+//
+//// TODO: mimic what I did for N_FUN if that works...
+//// // We use the 1 byte for the size because we don't know the
+//// // size of the global symbol without seeing the DWARF.
+//// SectionSP oso_fun_section_sp (new Section ( NULL, oso_module, // Module (the .o file)
+//// sect_id++, // Section ID starts at 0x10000 and increments so the section IDs don't overlap with the standard mach IDs
+//// exe_symbol->GetMangled().GetName(),// Name the section the same as the symbol for which is was generated!
+//// // &stsym_load_range, // Load offset is the offset into the executable section for the N_FUN from the debug map
+//// &stsym_file_range, // File section/offset is just the same os the symbol on the .o file
+//// 0, 0, 0));
+////
+//// // Now we add the new section to the .o file's sections as a child
+//// // of the section in which the N_SECT symbol exists.
+//// oso_stsym_section->GetChildren().AddSection(oso_fun_section_sp);
+//// comp_unit_info->debug_map_sections_sp->AddSection(oso_fun_section_sp);
+// }
+// }
+// }
+// break;
+ }
+ }
+ }
+#if defined(DEBUG_OSO_DMAP)
+ s << "OSO sections after:\n";
+ oso_objfile->GetSectionList()->Dump(&s, NULL, true);
+#endif
+ }
+ }
+ }
+ if (comp_unit_info->oso_symbol_vendor)
+ return (SymbolFileDWARF *)comp_unit_info->oso_symbol_vendor->GetSymbolFile();
+ return NULL;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::GetAbilities ()
+{
+ // 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)
+ {
+ const uint32_t dwarf_abilities = SymbolFile::CompileUnits |
+ SymbolFile::Functions |
+ SymbolFile::Blocks |
+ SymbolFile::GlobalVariables |
+ SymbolFile::LocalVariables |
+ SymbolFile::VariableTypes |
+ SymbolFile::LineTables;
+
+ for (uint32_t oso_idx=0; oso_idx<oso_index_count; ++oso_idx)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ if (oso_dwarf)
+ {
+ uint32_t oso_abilities = oso_dwarf->GetAbilities();
+ if ((oso_abilities & dwarf_abilities) == dwarf_abilities)
+ return oso_abilities;
+ }
+ }
+ }
+ 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)
+ {
+ if (m_compile_unit_infos[cu_idx].oso_compile_unit_sp.get() == NULL)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (cu_idx);
+ if (oso_dwarf)
+ {
+ // There is only one compile unit for N_OSO entry right now, so
+ // it will always exist at index zero.
+ m_compile_unit_infos[cu_idx].oso_compile_unit_sp = m_compile_unit_infos[cu_idx].oso_symbol_vendor->GetCompileUnitAtIndex (0);
+ }
+
+ if (m_compile_unit_infos[cu_idx].oso_compile_unit_sp.get() == NULL)
+ {
+ // We weren't able to get the DWARF for this N_OSO entry (the
+ // .o file may be missing or not at the specified path), make
+ // one up as best we can from the debug map. We set the uid
+ // of the compile unit to the symbol index with the MSBit set
+ // so that it doesn't collide with any uid values from the DWARF
+ Symbol *so_symbol = m_compile_unit_infos[cu_idx].so_symbol;
+ if (so_symbol)
+ {
+ m_compile_unit_infos[cu_idx].oso_compile_unit_sp.reset(new CompileUnit (m_obj_file->GetModule(),
+ NULL,
+ so_symbol->GetMangled().GetName().AsCString(),
+ cu_idx,
+ Language::Unknown));
+ }
+ }
+ }
+ comp_unit_sp = m_compile_unit_infos[cu_idx].oso_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].oso_compile_unit_sp.get())
+ return &m_compile_unit_infos[i];
+ }
+ return NULL;
+}
+
+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->ParseTypes (sc);
+ return 0;
+}
+
+
+
+Type*
+SymbolFileDWARFDebugMap::ResolveTypeUID(lldb::user_id_t type_uid)
+{
+ return NULL;
+}
+
+
+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();
+ sc.symbol = symtab->FindSymbolContainingFileAddress (exe_file_addr, &m_func_indexes[0], m_func_indexes.size());
+
+ if (sc.symbol != NULL)
+ {
+ resolved_flags |= eSymbolContextSymbol;
+
+ uint32_t oso_idx = 0;
+ CompileUnitInfo* comp_unit_info = GetCompileUnitInfoForSymbolWithIndex (sc.symbol->GetID(), &oso_idx);
+ if (comp_unit_info)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ ObjectFile *oso_objfile = GetObjectFileByOSOIndex (oso_idx);
+ if (oso_dwarf && oso_objfile)
+ {
+ SectionList *oso_section_list = oso_objfile->GetSectionList();
+
+
+ SectionSP oso_section_sp(oso_section_list->FindSectionByName(exe_so_addr.GetSection()->GetName()));
+ if (oso_section_sp)
+ {
+ SectionSP oso_symbol_section_sp (oso_section_sp->GetChildren().FindSectionContainingLinkedFileAddress (exe_file_addr));
+
+ if (oso_symbol_section_sp)
+ {
+ const addr_t linked_file_addr = oso_symbol_section_sp->GetLinkedFileAddress();
+ Address oso_so_addr (oso_symbol_section_sp.get(), exe_file_addr - linked_file_addr);
+ if (oso_so_addr.IsSectionOffset())
+ resolved_flags |= oso_dwarf->ResolveSymbolContext (oso_so_addr, resolve_scope, sc);
+ }
+ }
+ // Map the load address from in the executable back to a
+ // section/offset address in the .o file so we can do
+ // lookups in the .o DWARF.
+// Address oso_so_addr (exe_load_addr, false, comp_unit_info->debug_map_sections_sp.get());
+//
+// // Make sure we were able to resolve this back to a .o
+// // section offset address, and if so, resolve the context
+// // for everything that was asked for.
+// if (oso_so_addr.IsSectionOffset())
+// resolved_flags |= oso_dwarf->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)
+{
+ uint32_t initial = sc_list.GetSize();
+ const uint32_t cu_count = GetNumCompileUnits();
+
+ FileSpec so_file_spec;
+ for (uint32_t i=0; i<cu_count; ++i)
+ {
+ if (GetFileSpecForSO (i, so_file_spec))
+ {
+ // By passing false to the comparison we will be able to match
+ // and files given a filename only. If both file_spec and
+ // so_file_spec have directories, we will still do a full match.
+ if (FileSpec::Compare (file_spec, so_file_spec, false) == 0)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (i);
+
+ 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 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, true, max_matches, variables))
+ if (variables.GetSize() > max_matches)
+ break;
+ }
+ }
+ }
+ return variables.GetSize() - original_size;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::FindGlobalVariables (const ConstString &name, 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();
+
+ Symtab* symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+ std::vector<uint32_t> indexes;
+ const size_t match_count = m_obj_file->GetSymtab()->FindAllSymbolsWithNameAndType (name, eSymbolTypeGlobal, indexes);
+ if (match_count)
+ {
+ PrivateFindGlobalVariables (name, indexes, max_matches, variables);
+ }
+ }
+ // 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)
+{
+ return 0;
+}
+
+
+int
+SymbolFileDWARFDebugMap::SymbolContainsSymbolIndex (uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info)
+{
+ const uint32_t symbol_idx = *symbol_idx_ptr;
+
+ if (symbol_idx < comp_unit_info->so_symbol->GetID())
+ return -1;
+
+ if (symbol_idx < comp_unit_info->so_symbol->GetSiblingIndex())
+ 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), (comparison_function)SymbolContainsSymbolIndex);
+ }
+
+ 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;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::FindFunctions(const ConstString &name, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARFDebugMap::FindFunctions (name = %s)",
+ name.GetCString());
+
+
+ std::vector<uint32_t> indexes;
+ uint32_t initial_size = 0;
+ if (append)
+ initial_size = sc_list.GetSize();
+ else
+ sc_list.Clear();
+
+ const size_t match_count = m_obj_file->GetSymtab()->FindAllSymbolsWithNameAndType (name, eSymbolTypeFunction, indexes);
+ if (match_count > 0)
+ {
+ 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)
+ oso_dwarf->FindFunctions(name, true, sc_list);
+ }
+ }
+// Stream s(stdout);
+// sc_list.Dump(&s);
+ }
+
+ return sc_list.GetSize() - initial_size;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::FindFunctions (const RegularExpression& regex, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')",
+ regex.GetText());
+
+
+ return 0;
+}
+
+//
+//uint32_t
+//SymbolFileDWARFDebugMap::FindTypes (const SymbolContext& sc, const ConstString &name, 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, name, append, max_matches, encoding, udt_uid, types);
+// return 0;
+//}
+//
+//
+//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;
+//}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+SymbolFileDWARFDebugMap::GetPluginName()
+{
+ return "SymbolFileDWARFDebugMap";
+}
+
+const char *
+SymbolFileDWARFDebugMap::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+SymbolFileDWARFDebugMap::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+SymbolFileDWARFDebugMap::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+SymbolFileDWARFDebugMap::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
new file mode 100644
index 00000000000..0a312ab9f26
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -0,0 +1,186 @@
+//===-- 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 liblldb_SymbolFileDWARFDebugMap_h_
+#define liblldb_SymbolFileDWARFDebugMap_h_
+
+
+#include <vector>
+#include <bitset>
+#include "lldb/Symbol/SymbolFile.h"
+
+class SymbolFileDWARF;
+
+class SymbolFileDWARFDebugMap : public lldb_private::SymbolFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ 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 GetAbilities ();
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ virtual uint32_t GetNumCompileUnits ();
+ virtual lldb::CompUnitSP ParseCompileUnitAtIndex (uint32_t index);
+
+ 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 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, 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, bool append, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindFunctions (const lldb_private::RegularExpression& regex, bool append, lldb_private::SymbolContextList& sc_list);
+// virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types);
+// virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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:
+ enum
+ {
+ kHaveInitializedOSOs = (1 << 0),
+ kNumFlags
+ };
+
+ //------------------------------------------------------------------
+ // Class specific types
+ //------------------------------------------------------------------
+ struct CompileUnitInfo
+ {
+ lldb_private::FileSpec so_file;
+ lldb_private::Symbol *so_symbol;
+ lldb_private::Symbol *oso_symbol;
+ lldb::ModuleSP oso_module_sp;
+ lldb::CompUnitSP oso_compile_unit_sp;
+ lldb_private::SymbolVendor *oso_symbol_vendor;
+// lldb_private::shared_ptr<SymbolFileDWARF> oso_dwarf_sp;
+// lldb_private::shared_ptr<SymbolVendor> oso_dwarf_sp;
+ std::vector<uint32_t> function_indexes;
+ std::vector<uint32_t> static_indexes;
+ lldb::SharedPtr<lldb_private::SectionList>::Type debug_map_sections_sp;
+
+ CompileUnitInfo() :
+ so_file(),
+ so_symbol(NULL),
+ oso_symbol(NULL),
+ oso_module_sp(),
+ oso_compile_unit_sp(),
+ oso_symbol_vendor(NULL),
+// oso_dwarf_sp(),
+ function_indexes(),
+ static_indexes(),
+ debug_map_sections_sp()
+ {
+ }
+ };
+
+ //------------------------------------------------------------------
+ // Protected Member Functions
+ //------------------------------------------------------------------
+ void
+ InitOSO ();
+
+ bool
+ GetFileSpecForSO (uint32_t oso_idx, lldb_private::FileSpec &file_spec);
+
+ CompileUnitInfo *
+ GetCompUnitInfo (const lldb_private::SymbolContext& sc);
+
+ 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);
+
+ 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);
+
+ static int
+ SymbolContainsSymbolIndex (uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info);
+
+ uint32_t
+ PrivateFindGlobalVariables (const lldb_private::ConstString &name,
+ const std::vector<uint32_t> &name_symbol_indexes,
+ uint32_t max_matches,
+ lldb_private::VariableList& variables);
+
+ //------------------------------------------------------------------
+ // 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;
+};
+
+#endif // #ifndef liblldb_SymbolFileDWARFDebugMap_h_
diff --git a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
new file mode 100644
index 00000000000..d7da35675c7
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
@@ -0,0 +1,401 @@
+//===-- 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/ObjectFile.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Function.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+SymbolFileSymtab::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolFileSymtab::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+SymbolFileSymtab::GetPluginNameStatic()
+{
+ return "symbol-file.symtab";
+}
+
+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);
+}
+
+SymbolFileSymtab::SymbolFileSymtab(ObjectFile* obj_file) :
+ SymbolFile(obj_file),
+ m_source_indexes(),
+ m_func_indexes(),
+ m_code_indexes(),
+ m_data_indexes(),
+ m_addr_indexes()
+{
+}
+
+SymbolFileSymtab::~SymbolFileSymtab()
+{
+}
+
+
+uint32_t
+SymbolFileSymtab::GetAbilities ()
+{
+ uint32_t abilities = 0;
+ 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.
+ //----------------------------------------------------------------------
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeSourceFile, m_source_indexes);
+ if (!m_source_indexes.empty())
+ {
+ abilities |= CompileUnits;
+ }
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeFunction, m_func_indexes);
+ if (!m_func_indexes.empty())
+ {
+ symtab->SortSymbolIndexesByValue(m_func_indexes, true);
+ abilities |= Functions;
+ }
+
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeCode, m_code_indexes);
+ if (!m_code_indexes.empty())
+ {
+ symtab->SortSymbolIndexesByValue(m_code_indexes, true);
+ abilities |= Labels;
+ }
+
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeData, m_data_indexes);
+
+ if (!m_data_indexes.empty())
+ {
+ symtab->SortSymbolIndexesByValue(m_data_indexes, true);
+ abilities |= GlobalVariables;
+ }
+ }
+
+ 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 1;
+
+ // 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 (m_source_indexes.empty())
+ {
+ const FileSpec &obj_file_spec = m_obj_file->GetFileSpec();
+ if (obj_file_spec)
+ cu_sp.reset(new CompileUnit(m_obj_file->GetModule(), NULL, obj_file_spec, 0, Language::Unknown));
+
+ }
+ else 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, Language::Unknown));
+ }
+ return cu_sp;
+}
+
+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->GetValue(), 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->GetValue().GetOffset() - curr_symbol->GetValue().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;
+}
+
+
+
+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, 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, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileSymtab::FindFunctions (name = '%s')",
+ name.GetCString());
+
+ Symtab *symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+ const uint32_t start_size = sc_list.GetSize();
+ std::vector<uint32_t> symbol_indexes;
+ symtab->FindAllSymbolsWithNameAndType (name, eSymbolTypeFunction, symbol_indexes);
+ symtab->FindAllSymbolsWithNameAndType (name, eSymbolTypeCode, symbol_indexes);
+ const uint32_t num_matches = symbol_indexes.size();
+ if (num_matches)
+ {
+ SymbolContext sc(m_obj_file->GetModule());
+ for (uint32_t i=0; i<num_matches; i++)
+ {
+ sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
+ sc_list.Append(sc);
+ }
+ }
+ return sc_list.GetSize() - start_size;
+ }
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindFunctions(const RegularExpression& regex, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileSymtab::FindFunctions (regex = '%s')",
+ regex.GetText());
+
+ return 0;
+}
+
+//uint32_t
+//SymbolFileSymtab::FindTypes(const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+//{
+// return 0;
+//}
+//
+//uint32_t
+//SymbolFileSymtab::FindTypes(const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+//{
+// return 0;
+//}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+SymbolFileSymtab::GetPluginName()
+{
+ return "SymbolFileSymtab";
+}
+
+const char *
+SymbolFileSymtab::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolFileSymtab::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+SymbolFileSymtab::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+SymbolFileSymtab::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+SymbolFileSymtab::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
diff --git a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
new file mode 100644
index 00000000000..ac73f294585
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
@@ -0,0 +1,136 @@
+//===-- 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 <vector>
+
+class SymbolFileSymtab : public lldb_private::SymbolFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ 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 GetAbilities ();
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ virtual uint32_t
+ GetNumCompileUnits();
+
+ virtual lldb::CompUnitSP
+ ParseCompileUnitAtIndex(uint32_t index);
+
+ 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 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, 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, bool append, lldb_private::SymbolContextList& sc_list);
+
+ virtual uint32_t
+ FindFunctions(const lldb_private::RegularExpression& regex, bool append, lldb_private::SymbolContextList& sc_list);
+
+// virtual uint32_t
+// FindTypes(const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, bool append, uint32_t max_matches, lldb_private::Type::Encoding encoding, lldb::user_id_t udt_uid, lldb_private::TypeList& types);
+
+// virtual uint32_t
+// FindTypes(const lldb_private::SymbolContext& sc, const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::Type::Encoding encoding, lldb::user_id_t udt_uid, lldb_private::TypeList& types);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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:
+ std::vector<uint32_t> m_source_indexes;
+ std::vector<uint32_t> m_func_indexes;
+ std::vector<uint32_t> m_code_indexes;
+ std::vector<uint32_t> m_data_indexes;
+ std::vector<uint32_t> m_addr_indexes; // Anything that needs to go into an search by address
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (SymbolFileSymtab);
+};
+
+
+#endif // liblldb_SymbolFileSymtab_h_
diff --git a/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
new file mode 100644
index 00000000000..270d7ed0f5d
--- /dev/null
+++ b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
@@ -0,0 +1,339 @@
+//===-- SymbolVendorMacOSX.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolVendorMacOSX.h"
+
+#include <mach/machine.h> // DebugSymbols needs this on Leopard...
+
+#include <AvailabilityMacros.h>
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// SymbolVendorMacOSX constructor
+//----------------------------------------------------------------------
+SymbolVendorMacOSX::SymbolVendorMacOSX(Module *module) :
+ SymbolVendor(module)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SymbolVendorMacOSX::~SymbolVendorMacOSX()
+{
+}
+
+
+static bool
+UUIDsMatch(Module *module, ObjectFile *ofile)
+{
+ if (module && ofile)
+ {
+ // Make sure the UUIDs match
+ UUID dsym_uuid;
+ if (ofile->GetUUID(&dsym_uuid))
+ return dsym_uuid == module->GetUUID();
+ }
+ return false;
+}
+
+
+//ObjectFile *
+//LocateDSYMMachFileInDSYMBundle (Module* module, FileSpec& dsym_fspec)
+//{
+// ObjectFile *dsym_objfile = NULL;
+//
+// char path[PATH_MAX];
+//
+// if (dsym_fspec.GetPath(path, sizeof(path)))
+// {
+// size_t path_len = strlen(path);
+// const char *bundle_subpath = "/Contents/Resources/DWARF/";
+// if (path_len > 0)
+// {
+// if (path[path_len-1] == '/')
+// ::strncat (path, bundle_subpath + 1, sizeof(path));
+// else
+// ::strncat (path, bundle_subpath, sizeof(path));
+// ::strncat (path, dsym_fspec.GetFilename().AsCString(), sizeof(path));
+//
+// path_len = strlen(path);
+//
+// if (::strcasecmp (&path[path_len - strlen(".dSYM")], ".dSYM") == 0)
+// {
+// path[path_len - ::strlen(".dSYM")] = '\0';
+// dsym_fspec.SetFile(path);
+// dsym_objfile = ObjectFile::FindPlugin(module, &dsym_fspec, 0);
+// }
+// }
+// }
+// return dsym_objfile;
+//}
+//
+//CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url) __attribute__((weak_import));
+
+
+//ObjectFile *
+//FindDSYMUsingDebugSymbols (Module* module, FileSpec& dsym_fspec)
+//{
+// Timer scoped_locate("FindDSYMUsingDebugSymbols");
+// dsym_fspec.Clear();
+// ObjectFile *dsym_objfile = NULL;
+// if (module->GetUUID().IsValid())
+// {
+// // Try and locate the dSYM file using DebugSymbols first
+// const UInt8 *module_uuid = (const UInt8 *)module->GetUUID().GetBytes();
+// if (module_uuid != NULL)
+// {
+// CFUUIDRef module_uuid_ref;
+// module_uuid_ref = ::CFUUIDCreateWithBytes ( NULL,
+// module_uuid[0],
+// module_uuid[1],
+// module_uuid[2],
+// module_uuid[3],
+// module_uuid[4],
+// module_uuid[5],
+// module_uuid[6],
+// module_uuid[7],
+// module_uuid[8],
+// module_uuid[9],
+// module_uuid[10],
+// module_uuid[11],
+// module_uuid[12],
+// module_uuid[13],
+// module_uuid[14],
+// module_uuid[15]);
+//
+// if (module_uuid_ref)
+// {
+// CFURLRef dsym_url = NULL;
+// CFURLRef exec_url = NULL;
+//
+// // if (DBGCopyFullDSYMURLForUUID)
+// {
+// char exec_path[PATH_MAX];
+// if (module->GetFileSpec().GetPath(exec_path, sizeof(exec_path)))
+// {
+// exec_url = CFURLCreateFromFileSystemRepresentation ( NULL,
+// (const UInt8 *)exec_path,
+// strlen(exec_path),
+// FALSE);
+// }
+//
+// dsym_url = DBGCopyFullDSYMURLForUUID(module_uuid_ref, exec_url);
+// }
+// // else
+// // {
+// // dsym_url = DBGCopyDSYMURLForUUID(module_uuid_ref);
+// // }
+//
+// if (exec_url)
+// {
+// ::CFRelease (exec_url);
+// exec_url = NULL;
+// }
+//
+// ::CFRelease(module_uuid_ref);
+// module_uuid_ref = NULL;
+//
+// if (dsym_url)
+// {
+// char dsym_path[PATH_MAX];
+// Boolean success = CFURLGetFileSystemRepresentation (dsym_url, true, (UInt8*)dsym_path, sizeof(dsym_path)-1);
+//
+// ::CFRelease(dsym_url), dsym_url = NULL;
+//
+// if (success)
+// {
+// dsym_fspec.SetFile(dsym_path);
+//
+// // Some newer versions of DebugSymbols will return a full path into a dSYM bundle
+// // that points to the correct mach file within the dSYM bundle (MH_DSYM mach file
+// // type).
+// dsym_objfile = ObjectFile::FindPlugin(module, &dsym_fspec, 0);
+//
+// // Olders versions of DebugSymbols will return a path to a dSYM bundle.
+// if (dsym_objfile == NULL)
+// dsym_objfile = LocateDSYMMachFileInDSYMBundle (module, dsym_fspec);
+// }
+// }
+// }
+// }
+// }
+// return dsym_objfile;
+//}
+
+static void
+ReplaceDSYMSectionsWithExecutableSections (ObjectFile *exec_objfile, ObjectFile *dsym_objfile)
+{
+ // We need both the executable and the dSYM to live off of the
+ // same section lists. So we take all of the sections from the
+ // executable, and replace them in the dSYM. This allows section
+ // offset addresses that come from the dSYM to automatically
+ // get updated as images (shared libraries) get loaded and
+ // unloaded.
+ SectionList *exec_section_list = exec_objfile->GetSectionList();
+ SectionList *dsym_section_list = dsym_objfile->GetSectionList();
+ if (exec_section_list && dsym_section_list)
+ {
+ const uint32_t num_exec_sections = dsym_section_list->GetSize();
+ uint32_t exec_sect_idx;
+ for (exec_sect_idx = 0; exec_sect_idx < num_exec_sections; ++exec_sect_idx)
+ {
+ SectionSP exec_sect_sp(exec_section_list->GetSectionAtIndex(exec_sect_idx));
+ if (exec_sect_sp.get())
+ {
+ // Try and replace any sections that exist in both the executable
+ // and in the dSYM with those from the executable. If we fail to
+ // replace the one in the dSYM, then add the executable section to
+ // the dSYM.
+ if (dsym_section_list->ReplaceSection(exec_sect_sp->GetID(), exec_sect_sp, 0) == false)
+ dsym_section_list->AddSection(exec_sect_sp);
+ }
+ }
+ }
+}
+
+void
+SymbolVendorMacOSX::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolVendorMacOSX::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+SymbolVendorMacOSX::GetPluginNameStatic()
+{
+ return "symbol-vendor.macosx";
+}
+
+const char *
+SymbolVendorMacOSX::GetPluginDescriptionStatic()
+{
+ return "Symbol vendor for MacOSX 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*
+SymbolVendorMacOSX::CreateInstance(Module* module)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolVendorMacOSX::CreateInstance (module = %s/%s)",
+ module->GetFileSpec().GetDirectory().AsCString(),
+ module->GetFileSpec().GetFilename().AsCString());
+ SymbolVendorMacOSX* symbol_vendor = new SymbolVendorMacOSX(module);
+ if (symbol_vendor)
+ {
+ char path[PATH_MAX];
+ path[0] = '\0';
+
+ // Try and locate the dSYM file on Mac OS X
+ ObjectFile * obj_file = module->GetObjectFile();
+ if (obj_file)
+ {
+ Timer scoped_timer2 ("SymbolVendorMacOSX::CreateInstance () locate dSYM",
+ "SymbolVendorMacOSX::CreateInstance (module = %s/%s) locate dSYM",
+ module->GetFileSpec().GetDirectory().AsCString(),
+ module->GetFileSpec().GetFilename().AsCString());
+
+ FileSpec dsym_fspec;
+ std::auto_ptr<ObjectFile> dsym_objfile_ap;
+ const FileSpec &file_spec = obj_file->GetFileSpec();
+ if (file_spec)
+ {
+ dsym_fspec = Symbols::LocateExecutableSymbolFile (&file_spec, &module->GetArchitecture(), &module->GetUUID());
+
+ if (dsym_fspec)
+ {
+ dsym_objfile_ap.reset(ObjectFile::FindPlugin(module, &dsym_fspec, 0, dsym_fspec.GetByteSize()));
+ if (UUIDsMatch(module, dsym_objfile_ap.get()))
+ {
+ ReplaceDSYMSectionsWithExecutableSections (obj_file, dsym_objfile_ap.get());
+ symbol_vendor->AddSymbolFileRepresendation(dsym_objfile_ap.release());
+ return symbol_vendor;
+ }
+ }
+ }
+
+ // Just create our symbol vendor using the current objfile as this is either
+ // an executable with no dSYM (that we could locate), and executable with
+ // a dSYM that has a UUID that doesn't match, or it is a dSYM file itself.
+ symbol_vendor->AddSymbolFileRepresendation(obj_file);
+ }
+ }
+ return symbol_vendor;
+}
+
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+SymbolVendorMacOSX::GetPluginName()
+{
+ return "SymbolVendorMacOSX";
+}
+
+const char *
+SymbolVendorMacOSX::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolVendorMacOSX::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+SymbolVendorMacOSX::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+SymbolVendorMacOSX::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+SymbolVendorMacOSX::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
diff --git a/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h
new file mode 100644
index 00000000000..adbf6489e27
--- /dev/null
+++ b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h
@@ -0,0 +1,71 @@
+//===-- SymbolVendorMacOSX.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_SymbolVendorMacOSX_h_
+#define liblldb_SymbolVendorMacOSX_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+class SymbolVendorMacOSX : public lldb_private::SymbolVendor
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolVendor*
+ CreateInstance (lldb_private::Module *module);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolVendorMacOSX (lldb_private::Module *module);
+
+ virtual
+ ~SymbolVendorMacOSX();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ 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);
+
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (SymbolVendorMacOSX);
+};
+
+#endif // liblldb_SymbolVendorMacOSX_h_
diff --git a/lldb/source/Symbol/Block.cpp b/lldb/source/Symbol/Block.cpp
new file mode 100644
index 00000000000..321411940f4
--- /dev/null
+++ b/lldb/source/Symbol/Block.cpp
@@ -0,0 +1,641 @@
+//===-- 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/Symbol/Function.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Block::Block(user_id_t uid, uint32_t depth, BlockList* blocks) :
+ UserID(uid),
+ m_block_list(blocks),
+ m_depth(depth),
+ m_ranges(),
+ m_inlineInfoSP(),
+ m_variables()
+{
+}
+
+Block::Block(const Block& rhs) :
+ UserID(rhs),
+ m_block_list(rhs.m_block_list),
+ m_depth(rhs.m_depth),
+ m_ranges(rhs.m_ranges),
+ m_inlineInfoSP(rhs.m_inlineInfoSP),
+ m_variables(rhs.m_variables)
+{
+}
+
+const Block&
+Block::operator= (const Block& rhs)
+{
+ if (this != &rhs)
+ {
+ UserID::operator= (rhs);
+ m_block_list = rhs.m_block_list;
+ m_depth = rhs.m_depth;
+ m_ranges = rhs.m_ranges;
+ m_inlineInfoSP = rhs.m_inlineInfoSP;
+ m_variables = rhs.m_variables;
+ }
+ return *this;
+}
+
+Block::~Block ()
+{
+}
+
+void
+Block::Dump(Stream *s, addr_t base_addr, int32_t depth, bool show_context) const
+{
+ if (depth < 0)
+ {
+ // We have a depth that is less than zero, print our parent blocks
+ // first
+ m_block_list->Dump(s, GetParentUID(), depth + 1, show_context);
+ }
+
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ *s << "Block" << ((const UserID&)*this);
+ user_id_t parentID = GetParentUID();
+ const Block* parent_block = NULL;
+ if (parentID != Block::InvalidID)
+ {
+ parent_block = m_block_list->GetBlockByID(parentID);
+ s->Printf(", parent = {0x%8.8x}", parentID);
+ }
+ if (m_inlineInfoSP.get() != NULL)
+ m_inlineInfoSP->Dump(s);
+
+ if (!m_ranges.empty())
+ {
+ *s << ", ranges =";
+ std::vector<VMRange>::const_iterator pos;
+ std::vector<VMRange>::const_iterator end = m_ranges.end();
+ for (pos = m_ranges.begin(); pos != end; ++pos)
+ {
+ if (parent_block != NULL && parent_block->Contains(*pos) == false)
+ *s << '!';
+ else
+ *s << ' ';
+ pos->Dump(s, base_addr);
+ }
+ }
+ s->EOL();
+
+ if (depth > 0)
+ {
+ s->IndentMore();
+
+ if (m_variables.get())
+ {
+ m_variables->Dump(s, show_context);
+ }
+
+ uint32_t blockID = m_block_list->GetFirstChild(GetID());
+ while (blockID != Block::InvalidID)
+ {
+ m_block_list->Dump(s, blockID, depth - 1, show_context);
+
+ blockID = m_block_list->GetSibling(blockID);
+ }
+
+ s->IndentLess();
+ }
+
+}
+
+
+void
+Block::CalculateSymbolContext(SymbolContext* sc)
+{
+ sc->block = this;
+ m_block_list->GetFunction()->CalculateSymbolContext(sc);
+}
+
+void
+Block::DumpStopContext (Stream *s, const SymbolContext *sc)
+{
+ user_id_t parentID = GetParentUID();
+ Block* parent_block = NULL;
+ if (parentID != Block::InvalidID)
+ parent_block = m_block_list->GetBlockByID(parentID);
+
+ InlineFunctionInfo* inline_info = InlinedFunctionInfo ();
+ if (inline_info)
+ {
+ const Declaration &call_site = inline_info->GetCallSite();
+ if (sc)
+ {
+ // First frame, dump the first inline call site
+// if (call_site.IsValid())
+// {
+// s->PutCString(" at ");
+// call_site.DumpStopContext (s);
+// }
+ s->PutCString (" [inlined]");
+ }
+ s->EOL();
+ inline_info->DumpStopContext (s);
+ if (sc == NULL)
+ {
+ if (call_site.IsValid())
+ {
+ s->PutCString(" at ");
+ call_site.DumpStopContext (s);
+ }
+ }
+ }
+
+ if (sc)
+ {
+ // If we have any inlined functions, this will be the deepest most
+ // inlined location
+ if (sc->line_entry.IsValid())
+ {
+ s->PutCString(" at ");
+ sc->line_entry.DumpStopContext (s);
+ }
+ }
+ if (parent_block)
+ parent_block->Block::DumpStopContext (s, NULL);
+}
+
+
+void
+Block::DumpSymbolContext(Stream *s)
+{
+ m_block_list->GetFunction()->DumpSymbolContext(s);
+ s->Printf(", Block{0x%8.8x}", GetID());
+}
+
+bool
+Block::Contains (addr_t range_offset) const
+{
+ return VMRange::ContainsValue(m_ranges, range_offset);
+}
+
+bool
+Block::Contains (const VMRange& range) const
+{
+ return VMRange::ContainsRange(m_ranges, range);
+}
+
+
+
+bool
+BlockList::BlockContainsBlockWithID (const user_id_t block_id, const user_id_t find_block_id) const
+{
+ if (block_id == Block::InvalidID)
+ return false;
+
+ if (block_id == find_block_id)
+ return true;
+ else
+ {
+ user_id_t child_block_id = GetFirstChild(block_id);
+ while (child_block_id != Block::InvalidID)
+ {
+ if (BlockContainsBlockWithID (child_block_id, find_block_id))
+ return true;
+ child_block_id = GetSibling(child_block_id);
+ }
+ }
+
+ return false;
+}
+
+bool
+Block::ContainsBlockWithID (user_id_t block_id) const
+{
+ return m_block_list->BlockContainsBlockWithID (GetID(), block_id);
+}
+
+
+void
+Block::AddRange(addr_t start_offset, addr_t end_offset)
+{
+ m_ranges.resize(m_ranges.size()+1);
+ m_ranges.back().Reset(start_offset, end_offset);
+}
+
+InlineFunctionInfo*
+Block::InlinedFunctionInfo ()
+{
+ return m_inlineInfoSP.get();
+}
+
+const InlineFunctionInfo*
+Block::InlinedFunctionInfo () const
+{
+ return m_inlineInfoSP.get();
+}
+
+// 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.size() * sizeof(VMRange);
+ if (m_inlineInfoSP.get())
+ mem_size += m_inlineInfoSP->MemorySize();
+ if (m_variables.get())
+ mem_size += m_variables->MemorySize();
+ return mem_size;
+
+}
+
+user_id_t
+Block::GetParentUID() const
+{
+ return m_block_list->GetParent(GetID());
+}
+
+user_id_t
+Block::GetSiblingUID() const
+{
+ return m_block_list->GetSibling(GetID());
+}
+
+user_id_t
+Block::GetFirstChildUID() const
+{
+ return m_block_list->GetFirstChild(GetID());
+}
+
+user_id_t
+Block::AddChild(user_id_t userID)
+{
+ return m_block_list->AddChild(GetID(), userID);
+}
+
+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));
+}
+
+BlockList::BlockList(Function *function, const AddressRange& range) :
+ m_function(function),
+ m_range(range),
+ m_blocks()
+{
+}
+
+BlockList::~BlockList()
+{
+}
+
+AddressRange &
+BlockList::GetAddressRange()
+{
+ return m_range;
+}
+
+const AddressRange &
+BlockList::GetAddressRange() const
+{
+ return m_range;
+}
+
+void
+BlockList::Dump(Stream *s, user_id_t blockID, uint32_t depth, bool show_context) const
+{
+ const Block* block = GetBlockByID(blockID);
+ if (block)
+ block->Dump(s, m_range.GetBaseAddress().GetFileAddress(), depth, show_context);
+}
+
+Function *
+BlockList::GetFunction()
+{
+ return m_function;
+}
+
+
+const Function *
+BlockList::GetFunction() const
+{
+ return m_function;
+}
+
+user_id_t
+BlockList::GetParent(user_id_t blockID) const
+{
+ collection::const_iterator end = m_blocks.end();
+ collection::const_iterator begin = m_blocks.begin();
+ collection::const_iterator pos = std::find_if(begin, end, UserID::IDMatches(blockID));
+
+ if (pos != end && pos != begin && pos->Depth() > 0)
+ {
+ const uint32_t parent_depth = pos->Depth() - 1;
+
+ while (--pos >= begin)
+ {
+ if (pos->Depth() == parent_depth)
+ return pos->GetID();
+ }
+ }
+ return Block::InvalidID;
+}
+
+user_id_t
+BlockList::GetSibling(user_id_t blockID) const
+{
+ collection::const_iterator end = m_blocks.end();
+ collection::const_iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID));
+
+ if (pos != end)
+ {
+ const uint32_t sibling_depth = pos->Depth();
+ while (++pos != end)
+ {
+ uint32_t depth = pos->Depth();
+ if (depth == sibling_depth)
+ return pos->GetID();
+ if (depth < sibling_depth)
+ break;
+ }
+ }
+ return Block::InvalidID;
+}
+
+user_id_t
+BlockList::GetFirstChild(user_id_t blockID) const
+{
+ if (!m_blocks.empty())
+ {
+ if (blockID == Block::RootID)
+ {
+ return m_blocks.front().GetID();
+ }
+ else
+ {
+ collection::const_iterator end = m_blocks.end();
+ collection::const_iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID));
+
+ if (pos != end)
+ {
+ collection::const_iterator child_pos = pos + 1;
+ if (child_pos != end)
+ {
+ if (child_pos->Depth() == pos->Depth() + 1)
+ return child_pos->GetID();
+ }
+ }
+ }
+ }
+ return Block::InvalidID;
+}
+
+
+// Return the current number of bytes that this object occupies in memory
+size_t
+BlockList::MemorySize() const
+{
+ size_t mem_size = sizeof(BlockList);
+
+ collection::const_iterator pos, end = m_blocks.end();
+ for (pos = m_blocks.begin(); pos != end; ++pos)
+ mem_size += pos->MemorySize(); // Each block can vary in size
+
+ return mem_size;
+
+}
+
+user_id_t
+BlockList::AddChild (user_id_t parentID, user_id_t childID)
+{
+ bool added = false;
+ if (parentID == Block::RootID)
+ {
+ assert(m_blocks.empty());
+ Block block(childID, 0, this);
+ m_blocks.push_back(block);
+ added = true;
+ }
+ else
+ {
+ collection::iterator end = m_blocks.end();
+ collection::iterator parent_pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(parentID));
+ assert(parent_pos != end);
+ if (parent_pos != end)
+ {
+ const uint32_t parent_sibling_depth = parent_pos->Depth();
+
+ collection::iterator insert_pos = parent_pos;
+ collection::iterator prev_sibling = end;
+ while (++insert_pos != end)
+ {
+ if (insert_pos->Depth() <= parent_sibling_depth)
+ break;
+ }
+
+ Block child_block(childID, parent_pos->Depth() + 1, this);
+ collection::iterator child_pos = m_blocks.insert(insert_pos, child_block);
+ added = true;
+ }
+ }
+ if (added)
+ return childID;
+ return Block::InvalidID;
+}
+
+const Block *
+BlockList::GetBlockByID(user_id_t blockID) const
+{
+ if (m_blocks.empty())
+ return NULL;
+
+ if (blockID == Block::RootID)
+ blockID = m_blocks.front().GetID();
+
+ collection::const_iterator end = m_blocks.end();
+ collection::const_iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID));
+ if (pos != end)
+ return &(*pos);
+ return NULL;
+}
+
+Block *
+BlockList::GetBlockByID(user_id_t blockID)
+{
+ if (m_blocks.empty())
+ return NULL;
+
+ if (blockID == Block::RootID)
+ blockID = m_blocks.front().GetID();
+
+ collection::iterator end = m_blocks.end();
+ collection::iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID));
+ if (pos != end)
+ return &(*pos);
+ return NULL;
+}
+
+bool
+BlockList::AddRange(user_id_t blockID, addr_t start_offset, addr_t end_offset)
+{
+ Block *block = GetBlockByID(blockID);
+
+ if (block)
+ {
+ block->AddRange(start_offset, end_offset);
+ return true;
+ }
+ return false;
+}
+//
+//const Block *
+//BlockList::FindDeepestBlockForAddress (const Address &addr)
+//{
+// if (m_range.Contains(addr))
+// {
+// addr_t block_offset = addr.GetFileAddress() - m_range.GetBaseAddress().GetFileAddress();
+// collection::const_iterator pos, end = m_blocks.end();
+// collection::const_iterator deepest_match_pos = end;
+// for (pos = m_blocks.begin(); pos != end; ++pos)
+// {
+// if (pos->Contains (block_offset))
+// {
+// if (deepest_match_pos == end || deepest_match_pos->Depth() < pos->Depth())
+// deepest_match_pos = pos;
+// }
+// }
+// if (deepest_match_pos != end)
+// return &(*deepest_match_pos);
+// }
+// return NULL;
+//}
+//
+bool
+BlockList::SetInlinedFunctionInfo(user_id_t blockID, const char *name, const char *mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr)
+{
+ Block *block = GetBlockByID(blockID);
+
+ if (block)
+ {
+ block->SetInlinedFunctionInfo(name, mangled, decl_ptr, call_decl_ptr);
+ return true;
+ }
+ return false;
+}
+
+VariableListSP
+BlockList::GetVariableList(user_id_t blockID, bool get_child_variables, bool can_create)
+{
+ VariableListSP variable_list_sp;
+ Block *block = GetBlockByID(blockID);
+ if (block)
+ variable_list_sp = block->GetVariableList(get_child_variables, can_create);
+ return variable_list_sp;
+}
+
+bool
+BlockList::IsEmpty() const
+{
+ return m_blocks.empty();
+}
+
+
+
+bool
+BlockList::SetVariableList(user_id_t blockID, VariableListSP& variables)
+{
+ Block *block = GetBlockByID(blockID);
+ if (block)
+ {
+ block->SetVariableList(variables);
+ return true;
+ }
+ return false;
+
+}
+
+
+VariableListSP
+Block::GetVariableList (bool get_child_variables, bool can_create)
+{
+ VariableListSP variable_list_sp;
+ if (m_variables.get() == NULL && can_create)
+ {
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ assert(sc.module_sp);
+ sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
+ }
+
+ if (m_variables.get())
+ {
+ variable_list_sp.reset(new VariableList());
+ if (variable_list_sp.get())
+ variable_list_sp->AddVariables(m_variables.get());
+
+ if (get_child_variables)
+ {
+ user_id_t block_id = GetFirstChildUID();
+ while (block_id != Block::InvalidID)
+ {
+ Block *child_block = m_block_list->GetBlockByID(block_id);
+ assert(child_block);
+ VariableListSP child_block_variable_list(child_block->GetVariableList(get_child_variables, can_create));
+ if (child_block_variable_list.get())
+ variable_list_sp->AddVariables(child_block_variable_list.get());
+
+ block_id = child_block->GetSiblingUID();
+ }
+ }
+ }
+
+ return variable_list_sp;
+}
+
+uint32_t
+Block::AppendVariables (bool can_create, bool get_parent_variables, VariableList *variable_list)
+{
+ uint32_t num_variables_added = 0;
+ VariableListSP variable_list_sp(GetVariableList(false, can_create));
+
+ if (variable_list_sp.get())
+ {
+ num_variables_added = variable_list_sp->GetSize();
+ variable_list->AddVariables(variable_list_sp.get());
+ }
+
+ if (get_parent_variables)
+ {
+ user_id_t parentID = GetParentUID();
+ if (parentID != Block::InvalidID)
+ {
+ Block* parent_block = m_block_list->GetBlockByID(parentID);
+ if (parent_block)
+ num_variables_added += parent_block->AppendVariables (can_create, get_parent_variables, variable_list);
+ }
+ }
+ return num_variables_added;
+}
+
+
+void
+Block::SetVariableList(VariableListSP& variables)
+{
+ m_variables = variables;
+}
+
+uint32_t
+Block::Depth () const
+{
+ return m_depth;
+}
+
diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp
new file mode 100644
index 00000000000..be63de20c4c
--- /dev/null
+++ b/lldb/source/Symbol/ClangASTContext.cpp
@@ -0,0 +1,2552 @@
+//===-- 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 "ClangASTContext.h"
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/FileManager.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"
+
+// Project includes
+#include "lldb/Core/dwarf.h"
+
+using namespace lldb_private;
+using namespace llvm;
+using namespace clang;
+
+
+static void
+ParseLangArgs
+(
+ LangOptions &Opts,
+ FrontendOptions::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 == FrontendOptions::IK_Asm) {
+ Opts.AsmPreprocessor = 1;
+ } else if (IK == FrontendOptions::IK_ObjC ||
+ IK == FrontendOptions::IK_ObjCXX ||
+ IK == FrontendOptions::IK_PreprocessedObjC ||
+ IK == FrontendOptions::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 FrontendOptions::IK_None:
+ case FrontendOptions::IK_AST:
+ assert(0 && "Invalid input kind!");
+ case FrontendOptions::IK_OpenCL:
+ LangStd = LangStandard::lang_opencl;
+ break;
+ case FrontendOptions::IK_Asm:
+ case FrontendOptions::IK_C:
+ case FrontendOptions::IK_PreprocessedC:
+ case FrontendOptions::IK_ObjC:
+ case FrontendOptions::IK_PreprocessedObjC:
+ LangStd = LangStandard::lang_gnu99;
+ break;
+ case FrontendOptions::IK_CXX:
+ case FrontendOptions::IK_PreprocessedCXX:
+ case FrontendOptions::IK_ObjCXX:
+ case FrontendOptions::IK_PreprocessedObjCXX:
+ LangStd = LangStandard::lang_gnucxx98;
+ break;
+ }
+ }
+
+ const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
+ Opts.BCPLComment = Std.hasBCPLComments();
+ Opts.C99 = Std.isC99();
+ Opts.CPlusPlus = Std.isCPlusPlus();
+ Opts.CPlusPlus0x = Std.isCPlusPlus0x();
+ Opts.Digraphs = Std.hasDigraphs();
+ Opts.GNUMode = Std.isGNUMode();
+ Opts.GNUInline = !Std.isC99();
+ Opts.HexFloats = Std.hasHexFloats();
+ Opts.ImplicitInt = Std.hasImplicitInt();
+
+ // 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.setVisibilityMode(LangOptions::Default);
+// 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.NoInline = !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 constructor
+//----------------------------------------------------------------------
+//ClangASTContext::ClangASTContext(Module *module) :
+// m_target_triple(),
+// m_ast_context_ap(),
+// m_language_options_ap(),
+// m_source_manager_ap(),
+// m_target_info_ap(),
+// m_identifier_table_ap(),
+// m_selector_table_ap(),
+// m_builtins_ap()
+//{
+// if (module)
+// {
+// ObjectFile * objfile = module->GetObjectFile();
+// if (objfile)
+// objfile->GetTargetTriple(m_target_triple);
+// }
+//}
+
+//ClangASTContext::ClangASTContext(const ConstString& target_triple) :
+// m_target_triple(target_triple),
+// m_ast_context_ap(),
+// m_language_options_ap(),
+// m_source_manager_ap(),
+// m_target_info_ap(),
+// m_identifier_table_ap(),
+// m_selector_table_ap(),
+// m_builtins_ap()
+//{
+//}
+ClangASTContext::ClangASTContext(const char *target_triple) :
+ m_target_triple(),
+ m_ast_context_ap(),
+ m_language_options_ap(),
+ m_source_manager_ap(),
+ m_diagnostic_ap(),
+ m_target_options_ap(),
+ m_target_info_ap(),
+ m_identifier_table_ap(),
+ m_selector_table_ap(),
+ m_builtins_ap()
+{
+ if (target_triple && target_triple[0])
+ m_target_triple.assign (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_ap.reset();
+ m_diagnostic_ap.reset();
+ m_source_manager_ap.reset();
+ m_language_options_ap.reset();
+ m_ast_context_ap.reset();
+}
+
+
+void
+ClangASTContext::Clear()
+{
+ m_ast_context_ap.reset();
+ m_language_options_ap.reset();
+ m_source_manager_ap.reset();
+ m_diagnostic_ap.reset();
+ m_target_options_ap.reset();
+ m_target_info_ap.reset();
+ m_identifier_table_ap.reset();
+ m_selector_table_ap.reset();
+ m_builtins_ap.reset();
+}
+
+const char *
+ClangASTContext::GetTargetTriple ()
+{
+ return m_target_triple.c_str();
+}
+
+void
+ClangASTContext::SetTargetTriple (const char *target_triple)
+{
+ Clear();
+ m_target_triple.assign(target_triple);
+}
+
+
+ASTContext *
+ClangASTContext::getASTContext()
+{
+ if (m_ast_context_ap.get() == NULL)
+ {
+ m_ast_context_ap.reset(
+ new ASTContext(
+ *getLanguageOptions(),
+ *getSourceManager(),
+ *getTargetInfo(),
+ *getIdentifierTable(),
+ *getSelectorTable(),
+ *getBuiltinContext()));
+ }
+ return m_ast_context_ap.get();
+}
+
+Builtin::Context *
+ClangASTContext::getBuiltinContext()
+{
+ if (m_builtins_ap.get() == NULL)
+ m_builtins_ap.reset (new Builtin::Context(*getTargetInfo()));
+ 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, FrontendOptions::IK_ObjCXX);
+// InitializeLangOptions(*m_language_options_ap, FrontendOptions::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();
+}
+
+SourceManager *
+ClangASTContext::getSourceManager()
+{
+ if (m_source_manager_ap.get() == NULL)
+ m_source_manager_ap.reset(new SourceManager(*getDiagnostic()));
+ return m_source_manager_ap.get();
+}
+
+Diagnostic *
+ClangASTContext::getDiagnostic()
+{
+ if (m_diagnostic_ap.get() == NULL)
+ m_diagnostic_ap.reset(new Diagnostic());
+ return m_diagnostic_ap.get();
+}
+
+TargetOptions *
+ClangASTContext::getTargetOptions()
+{
+ if (m_target_options_ap.get() == NULL && !m_target_triple.empty())
+ {
+ m_target_options_ap.reset (new TargetOptions());
+ if (m_target_options_ap.get())
+ m_target_options_ap->Triple = m_target_triple;
+ }
+ return m_target_options_ap.get();
+}
+
+
+TargetInfo *
+ClangASTContext::getTargetInfo()
+{
+ // target_triple should be something like "x86_64-apple-darwin10"
+ if (m_target_info_ap.get() == NULL && !m_target_triple.empty())
+ m_target_info_ap.reset (TargetInfo::CreateTargetInfo(*getDiagnostic(), *getTargetOptions()));
+ return m_target_info_ap.get();
+}
+
+#pragma mark Basic Types
+
+static inline bool
+QualTypeMatchesBitSize(const uint64_t bit_size, ASTContext *ast_context, QualType qual_type)
+{
+ uint64_t qual_type_bit_size = ast_context->getTypeSize(qual_type);
+ if (qual_type_bit_size == bit_size)
+ return true;
+ return false;
+}
+
+void *
+ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (lldb::Encoding encoding, uint32_t bit_size)
+{
+ ASTContext *ast_context = getASTContext();
+
+ assert (ast_context != NULL);
+
+ return GetBuiltinTypeForEncodingAndBitSize (ast_context, encoding, bit_size);
+}
+
+void *
+ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (clang::ASTContext *ast_context, lldb::Encoding encoding, uint32_t bit_size)
+{
+ if (!ast_context)
+ return NULL;
+
+ switch (encoding)
+ {
+ case lldb::eEncodingInvalid:
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->VoidPtrTy))
+ return ast_context->VoidPtrTy.getAsOpaquePtr();
+ break;
+
+ case lldb::eEncodingUint:
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy))
+ return ast_context->UnsignedCharTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy))
+ return ast_context->UnsignedShortTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy))
+ return ast_context->UnsignedIntTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy))
+ return ast_context->UnsignedLongTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy))
+ return ast_context->UnsignedLongLongTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty))
+ return ast_context->UnsignedInt128Ty.getAsOpaquePtr();
+ break;
+
+ case lldb::eEncodingSint:
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy))
+ return ast_context->CharTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy))
+ return ast_context->ShortTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy))
+ return ast_context->IntTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy))
+ return ast_context->LongTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy))
+ return ast_context->LongLongTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty))
+ return ast_context->Int128Ty.getAsOpaquePtr();
+ break;
+
+ case lldb::eEncodingIEEE754:
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatTy))
+ return ast_context->FloatTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleTy))
+ return ast_context->DoubleTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleTy))
+ return ast_context->LongDoubleTy.getAsOpaquePtr();
+ break;
+
+ case lldb::eEncodingVector:
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+void *
+ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name, uint32_t dw_ate, uint32_t bit_size)
+{
+ ASTContext *ast_context = getASTContext();
+
+ #define streq(a,b) strcmp(a,b) == 0
+ assert (ast_context != NULL);
+ if (ast_context)
+ {
+ switch (dw_ate)
+ {
+ default:
+ break;
+
+ case DW_ATE_address:
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->VoidPtrTy))
+ return ast_context->VoidPtrTy.getAsOpaquePtr();
+ break;
+
+ case DW_ATE_boolean:
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->BoolTy))
+ return ast_context->BoolTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy))
+ return ast_context->UnsignedCharTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy))
+ return ast_context->UnsignedShortTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy))
+ return ast_context->UnsignedIntTy.getAsOpaquePtr();
+ break;
+
+ case DW_ATE_complex_float:
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatComplexTy))
+ return ast_context->FloatComplexTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleComplexTy))
+ return ast_context->DoubleComplexTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleComplexTy))
+ return ast_context->LongDoubleComplexTy.getAsOpaquePtr();
+ break;
+
+ case DW_ATE_float:
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatTy))
+ return ast_context->FloatTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleTy))
+ return ast_context->DoubleTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleTy))
+ return ast_context->LongDoubleTy.getAsOpaquePtr();
+ break;
+
+ case DW_ATE_signed:
+ if (type_name)
+ {
+ if (streq(type_name, "int") ||
+ streq(type_name, "signed int"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy))
+ return ast_context->IntTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty))
+ return ast_context->Int128Ty.getAsOpaquePtr();
+ }
+
+ if (streq(type_name, "long int") ||
+ streq(type_name, "long long int") ||
+ streq(type_name, "signed long long"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy))
+ return ast_context->LongTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy))
+ return ast_context->LongLongTy.getAsOpaquePtr();
+ }
+
+ if (streq(type_name, "short") ||
+ streq(type_name, "short int") ||
+ streq(type_name, "signed short") ||
+ streq(type_name, "short signed int"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy))
+ return ast_context->ShortTy.getAsOpaquePtr();
+ }
+
+ if (streq(type_name, "char") ||
+ streq(type_name, "signed char"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy))
+ return ast_context->CharTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy))
+ return ast_context->SignedCharTy.getAsOpaquePtr();
+ }
+
+ if (streq(type_name, "wchar_t"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->WCharTy))
+ return ast_context->WCharTy.getAsOpaquePtr();
+ }
+
+ }
+ // We weren't able to match up a type name, just search by size
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy))
+ return ast_context->CharTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy))
+ return ast_context->ShortTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy))
+ return ast_context->IntTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy))
+ return ast_context->LongTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy))
+ return ast_context->LongLongTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty))
+ return ast_context->Int128Ty.getAsOpaquePtr();
+ break;
+
+ case DW_ATE_signed_char:
+ if (type_name)
+ {
+ if (streq(type_name, "signed char"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy))
+ return ast_context->SignedCharTy.getAsOpaquePtr();
+ }
+ }
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy))
+ return ast_context->CharTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy))
+ return ast_context->SignedCharTy.getAsOpaquePtr();
+ break;
+
+ case DW_ATE_unsigned:
+ if (type_name)
+ {
+ if (streq(type_name, "unsigned int"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy))
+ return ast_context->UnsignedIntTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty))
+ return ast_context->UnsignedInt128Ty.getAsOpaquePtr();
+ }
+
+ if (streq(type_name, "unsigned int") ||
+ streq(type_name, "long unsigned int") ||
+ streq(type_name, "unsigned long long"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy))
+ return ast_context->UnsignedLongTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy))
+ return ast_context->UnsignedLongLongTy.getAsOpaquePtr();
+ }
+
+ if (streq(type_name, "unsigned short") ||
+ streq(type_name, "short unsigned int"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy))
+ return ast_context->UnsignedShortTy.getAsOpaquePtr();
+ }
+ if (streq(type_name, "unsigned char"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy))
+ return ast_context->UnsignedCharTy.getAsOpaquePtr();
+ }
+
+ }
+ // We weren't able to match up a type name, just search by size
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy))
+ return ast_context->UnsignedCharTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy))
+ return ast_context->UnsignedShortTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy))
+ return ast_context->UnsignedIntTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy))
+ return ast_context->UnsignedLongTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy))
+ return ast_context->UnsignedLongLongTy.getAsOpaquePtr();
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty))
+ return ast_context->UnsignedInt128Ty.getAsOpaquePtr();
+ break;
+
+ case DW_ATE_unsigned_char:
+ if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy))
+ return ast_context->UnsignedCharTy.getAsOpaquePtr();
+ break;
+
+ case DW_ATE_imaginary_float:
+ break;
+ }
+ }
+ // This assert should fire for anything that we don't catch above so we know
+ // to fix any issues we run into.
+ assert (!"error: ClangASTContext::GetClangTypeForDWARFEncodingAndSize() contains an unhandled encoding. Fix this ASAP!");
+ return NULL;
+}
+
+void *
+ClangASTContext::GetVoidBuiltInType()
+{
+ return getASTContext()->VoidTy.getAsOpaquePtr();
+}
+
+void *
+ClangASTContext::GetCStringType (bool is_const)
+{
+ QualType char_type(getASTContext()->CharTy);
+
+ if (is_const)
+ char_type.addConst();
+
+ return getASTContext()->getPointerType(char_type).getAsOpaquePtr();
+}
+
+void *
+ClangASTContext::GetVoidPtrType (bool is_const)
+{
+ return GetVoidPtrType(getASTContext(), is_const);
+}
+
+void *
+ClangASTContext::GetVoidPtrType (clang::ASTContext *ast_context, bool is_const)
+{
+ QualType void_ptr_type(ast_context->VoidPtrTy);
+
+ if (is_const)
+ void_ptr_type.addConst();
+
+ return void_ptr_type.getAsOpaquePtr();
+}
+
+void *
+ClangASTContext::CopyType(clang::ASTContext *dest_context,
+ clang::ASTContext *source_context,
+ void * clang_type)
+{
+ Diagnostic diagnostics;
+ FileManager file_manager;
+ ASTImporter importer(diagnostics,
+ *dest_context, file_manager,
+ *source_context, file_manager);
+ QualType ret = importer.Import(QualType::getFromOpaquePtr(clang_type));
+ return ret.getAsOpaquePtr();
+}
+
+#pragma mark CVR modifiers
+
+void *
+ClangASTContext::AddConstModifier (void *clang_type)
+{
+ if (clang_type)
+ {
+ QualType result(QualType::getFromOpaquePtr(clang_type));
+ result.addConst();
+ return result.getAsOpaquePtr();
+ }
+ return NULL;
+}
+
+void *
+ClangASTContext::AddRestrictModifier (void *clang_type)
+{
+ if (clang_type)
+ {
+ QualType result(QualType::getFromOpaquePtr(clang_type));
+ result.getQualifiers().setRestrict (true);
+ return result.getAsOpaquePtr();
+ }
+ return NULL;
+}
+
+void *
+ClangASTContext::AddVolatileModifier (void *clang_type)
+{
+ if (clang_type)
+ {
+ QualType result(QualType::getFromOpaquePtr(clang_type));
+ result.getQualifiers().setVolatile (true);
+ return result.getAsOpaquePtr();
+ }
+ return NULL;
+}
+
+#pragma mark Structure, Unions, Classes
+
+void *
+ClangASTContext::CreateRecordType (const char *name, int kind, DeclContext *decl_ctx)
+{
+ ASTContext *ast_context = getASTContext();
+ assert (ast_context != NULL);
+
+ if (decl_ctx == NULL)
+ decl_ctx = ast_context->getTranslationUnitDecl();
+
+ // 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_context,
+ (TagDecl::TagKind)kind,
+ decl_ctx,
+ SourceLocation(),
+ name && name[0] ? &ast_context->Idents.get(name) : NULL);
+
+ return ast_context->getTagDeclType(decl).getAsOpaquePtr();
+}
+
+bool
+ClangASTContext::AddFieldToRecordType (void * record_clang_type, const char *name, void * field_type, int access, uint32_t bitfield_bit_size)
+{
+ if (record_clang_type == NULL || field_type == NULL)
+ return false;
+
+ ASTContext *ast_context = getASTContext();
+ IdentifierTable *identifier_table = getIdentifierTable();
+
+ assert (ast_context != NULL);
+ assert (identifier_table != NULL);
+
+ QualType record_qual_type(QualType::getFromOpaquePtr(record_clang_type));
+
+ Type *clang_type = record_qual_type.getTypePtr();
+ if (clang_type)
+ {
+ const RecordType *record_type = dyn_cast<RecordType>(clang_type);
+
+ if (record_type)
+ {
+ RecordDecl *record_decl = record_type->getDecl();
+
+ CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ if (cxx_record_decl)
+ cxx_record_decl->setEmpty (false);
+
+ clang::Expr *bit_width = NULL;
+ if (bitfield_bit_size != 0)
+ {
+ APInt bitfield_bit_size_apint(ast_context->getTypeSize(ast_context->IntTy), bitfield_bit_size);
+ bit_width = new (*ast_context)IntegerLiteral (bitfield_bit_size_apint, ast_context->IntTy, SourceLocation());
+ }
+ FieldDecl *field = FieldDecl::Create(*ast_context,
+ record_decl,
+ SourceLocation(),
+ name ? &identifier_table->get(name) : NULL, // Identifier
+ QualType::getFromOpaquePtr(field_type), // Field type
+ NULL, // DeclaratorInfo *
+ bit_width, // BitWidth
+ false); // Mutable
+
+ field->setAccess((AccessSpecifier)access);
+
+ if (field)
+ {
+ record_decl->addDecl(field);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTContext::FieldIsBitfield (FieldDecl* field, uint32_t& bitfield_bit_size)
+{
+ return FieldIsBitfield(getASTContext(), field, bitfield_bit_size);
+}
+
+bool
+ClangASTContext::FieldIsBitfield
+(
+ ASTContext *ast_context,
+ FieldDecl* field,
+ uint32_t& bitfield_bit_size
+)
+{
+ if (ast_context == 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_context))
+ {
+ 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;
+}
+
+void
+ClangASTContext::SetDefaultAccessForRecordFields (void *clang_qual_type, int default_accessibility, int *assigned_accessibilities, size_t num_assigned_accessibilities)
+{
+ if (clang_qual_type)
+ {
+ QualType qual_type(QualType::getFromOpaquePtr(clang_qual_type));
+ Type *clang_type = qual_type.getTypePtr();
+ if (clang_type)
+ {
+ RecordType *record_type = dyn_cast<RecordType>(clang_type);
+ if (record_type)
+ {
+ RecordDecl *record_decl = record_type->getDecl();
+ 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);
+ }
+ }
+ }
+ }
+ }
+}
+
+#pragma mark C++ Base Classes
+
+CXXBaseSpecifier *
+ClangASTContext::CreateBaseClassSpecifier (void *base_class_type, int access, bool is_virtual, bool base_of_class)
+{
+ if (base_class_type)
+ return new CXXBaseSpecifier(SourceRange(), is_virtual, base_of_class, (AccessSpecifier)access, QualType::getFromOpaquePtr(base_class_type));
+ return NULL;
+}
+
+bool
+ClangASTContext::SetBaseClassesForClassType (void *class_clang_type, CXXBaseSpecifier const * const *base_classes, unsigned num_base_classes)
+{
+ if (class_clang_type)
+ {
+ ASTContext *ast_context = getASTContext();
+ IdentifierTable *identifier_table = getIdentifierTable();
+
+ assert (ast_context != NULL);
+ assert (identifier_table != NULL);
+
+ Type *clang_type = QualType::getFromOpaquePtr(class_clang_type).getTypePtr();
+ if (clang_type)
+ {
+ RecordType *record_type = dyn_cast<RecordType>(clang_type);
+ if (record_type)
+ {
+ CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_type->getDecl());
+ if (cxx_record_decl)
+ {
+ //cxx_record_decl->setEmpty (false);
+ cxx_record_decl->setBases(base_classes, num_base_classes);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+#pragma mark Aggregate Types
+
+bool
+ClangASTContext::IsAggregateType (void *clang_type)
+{
+ if (clang_type == NULL)
+ return false;
+
+ QualType qual_type (QualType::getFromOpaquePtr(clang_type));
+
+ if (qual_type->isAggregateType ())
+ return true;
+
+ switch (qual_type->getTypeClass())
+ {
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::ConstantArray:
+ case Type::ExtVector:
+ case Type::Vector:
+ case Type::Record:
+ return true;
+
+ case Type::Typedef:
+ return ClangASTContext::IsAggregateType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr());
+
+ default:
+ break;
+ }
+ // The clang type does have a value
+ return false;
+}
+
+uint32_t
+ClangASTContext::GetNumChildren (void *clang_qual_type, bool omit_empty_base_classes)
+{
+ if (clang_qual_type == NULL)
+ return 0;
+
+ uint32_t num_children = 0;
+ QualType qual_type(QualType::getFromOpaquePtr(clang_qual_type));
+ switch (qual_type->getTypeClass())
+ {
+ case Type::Record:
+ {
+ 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 (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 Type::ConstantArray:
+ num_children = cast<ConstantArrayType>(qual_type.getTypePtr())->getSize().getLimitedValue();
+ break;
+
+ case Type::Pointer:
+ {
+ PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr());
+ QualType pointee_type = pointer_type->getPointeeType();
+ uint32_t num_pointee_children = ClangASTContext::GetNumChildren (pointee_type.getAsOpaquePtr(), 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 Type::Typedef:
+ num_children = ClangASTContext::GetNumChildren (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), omit_empty_base_classes);
+ break;
+
+ default:
+ break;
+ }
+ return num_children;
+}
+
+
+void *
+ClangASTContext::GetChildClangTypeAtIndex
+(
+ const char *parent_name,
+ void *parent_clang_type,
+ uint32_t idx,
+ bool transparent_pointers,
+ bool omit_empty_base_classes,
+ 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
+)
+{
+ if (parent_clang_type)
+
+ return GetChildClangTypeAtIndex (getASTContext(),
+ parent_name,
+ parent_clang_type,
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset);
+ return NULL;
+}
+
+void *
+ClangASTContext::GetChildClangTypeAtIndex
+(
+ ASTContext *ast_context,
+ const char *parent_name,
+ void *parent_clang_type,
+ uint32_t idx,
+ bool transparent_pointers,
+ bool omit_empty_base_classes,
+ 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
+)
+{
+ if (parent_clang_type == NULL)
+ return NULL;
+
+ if (idx < ClangASTContext::GetNumChildren (parent_clang_type, omit_empty_base_classes))
+ {
+ uint32_t bit_offset;
+ child_bitfield_bit_size = 0;
+ child_bitfield_bit_offset = 0;
+ QualType parent_qual_type(QualType::getFromOpaquePtr(parent_clang_type));
+ switch (parent_qual_type->getTypeClass())
+ {
+ case Type::Record:
+ {
+ const RecordType *record_type = cast<RecordType>(parent_qual_type.getTypePtr());
+ const RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ const ASTRecordLayout &record_layout = ast_context->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 (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);
+ else
+ bit_offset = record_layout.getBaseClassOffset(base_class_decl);
+
+ // Base classes should be a multiple of 8 bits in size
+ assert (bit_offset % 8 == 0);
+ child_byte_offset = bit_offset/8;
+ std::string base_class_type_name(base_class->getType().getAsString());
+
+ child_name.assign(base_class_type_name.c_str());
+
+ uint64_t clang_type_info_bit_size = ast_context->getTypeSize(base_class->getType());
+
+ // Base classes biut sizes should be a multiple of 8 bits in size
+ assert (clang_type_info_bit_size % 8 == 0);
+ child_byte_size = clang_type_info_bit_size / 8;
+ return base_class->getType().getAsOpaquePtr();
+ }
+ // We don't increment the child index in the for loop since we might
+ // be skipping empty base classes
+ ++child_idx;
+ }
+ }
+ const unsigned num_fields = record_layout.getFieldCount();
+
+ // 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.
+ std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(field->getType());
+ assert(field_idx < num_fields);
+
+ child_byte_size = field_type_info.first / 8;
+
+ // 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 (ast_context, *field, child_bitfield_bit_size))
+ child_bitfield_bit_offset = bit_offset % 8;
+
+ return field->getType().getAsOpaquePtr();
+ }
+ }
+ }
+ break;
+
+ case 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_context->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 Type::Pointer:
+ {
+ PointerType *pointer_type = cast<PointerType>(parent_qual_type.getTypePtr());
+ QualType pointee_type = pointer_type->getPointeeType();
+
+ if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
+ {
+ return GetChildClangTypeAtIndex (ast_context,
+ parent_name,
+ pointer_type->getPointeeType().getAsOpaquePtr(),
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset);
+ }
+ 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_context->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 Type::Typedef:
+ return GetChildClangTypeAtIndex (ast_context,
+ parent_name,
+ cast<TypedefType>(parent_qual_type)->LookThroughTypedefs().getAsOpaquePtr(),
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset);
+ break;
+
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+static inline bool
+BaseSpecifierIsEmpty (const CXXBaseSpecifier *b)
+{
+ return ClangASTContext::RecordHasFields(cast<CXXRecordDecl>(b->getType()->getAs<RecordType>()->getDecl())) == false;
+}
+
+static uint32_t
+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;
+}
+
+
+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 = GetNumBaseClasses (dyn_cast<CXXRecordDecl>(record_decl), omit_empty_base_classes);
+
+// const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+//
+//// printf ("GetIndexForRecordChild (%s, %s)\n", record_decl->getNameAsCString(), canonical_decl->getNameAsCString());
+// 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",
+//// record_decl->getNameAsCString(),
+//// canonical_decl->getNameAsCString(),
+//// child_idx,
+//// base_class->getType()->getAs<RecordType>()->getDecl()->getNameAsCString());
+//
+//
+// CXXRecordDecl *curr_base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+// if (curr_base_class_decl == canonical_decl)
+// {
+// return child_idx;
+// }
+// ++child_idx;
+// }
+// }
+//
+// const uint32_t num_bases = child_idx;
+ RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end();
+ field != field_end;
+ ++field, ++child_idx)
+ {
+// printf ("GetIndexForRecordChild (%s, %s) field[%u] = %s\n",
+// record_decl->getNameAsCString(),
+// canonical_decl->getNameAsCString(),
+// child_idx - num_bases,
+// field->getNameAsCString());
+
+ 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
+ClangASTContext::GetIndexOfChildMemberWithName
+(
+ ASTContext *ast_context,
+ void *clang_type,
+ const char *name,
+ bool omit_empty_base_classes,
+ std::vector<uint32_t>& child_indexes
+)
+{
+ if (clang_type && name && name[0])
+ {
+ QualType qual_type(QualType::getFromOpaquePtr(clang_type));
+ switch (qual_type->getTypeClass())
+ {
+ case Type::Record:
+ {
+ 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 + 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 = ast_context->Idents.get(name, name + strlen (name));
+ DeclarationName decl_name(&ident_ref);
+
+ CXXBasePaths paths;
+ if (cxx_record_decl->lookupInBases(CXXRecordDecl::FindOrdinaryMember,
+ decl_name.getAsOpaquePtr(),
+ paths))
+ {
+ uint32_t child_idx;
+ 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());
+ }
+ }
+ DeclContext::lookup_iterator named_decl_pos;
+ for (named_decl_pos = path->Decls.first;
+ named_decl_pos != path->Decls.second && parent_record_decl;
+ ++named_decl_pos)
+ {
+ //printf ("path[%zu] = %s\n", child_indexes.size(), (*named_decl_pos)->getNameAsCString());
+
+ child_idx = GetIndexForRecordChild (parent_record_decl, *named_decl_pos, 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 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_context->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 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_context,
+// mem_ptr_type->getPointeeType().getAsOpaquePtr(),
+// name);
+// }
+// }
+// break;
+//
+ case Type::LValueReference:
+ case Type::RValueReference:
+ {
+ ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
+ QualType pointee_type = reference_type->getPointeeType();
+
+ if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
+ {
+ return GetIndexOfChildMemberWithName (ast_context,
+ reference_type->getPointeeType().getAsOpaquePtr(),
+ name,
+ omit_empty_base_classes,
+ child_indexes);
+ }
+ }
+ break;
+
+ case Type::Pointer:
+ {
+ PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr());
+ QualType pointee_type = pointer_type->getPointeeType();
+
+ if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
+ {
+ return GetIndexOfChildMemberWithName (ast_context,
+ pointer_type->getPointeeType().getAsOpaquePtr(),
+ name,
+ omit_empty_base_classes,
+ child_indexes);
+ }
+ 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_context->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 Type::Typedef:
+ return GetIndexOfChildMemberWithName (ast_context,
+ cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(),
+ 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
+ClangASTContext::GetIndexOfChildWithName
+(
+ ASTContext *ast_context,
+ void *clang_type,
+ const char *name,
+ bool omit_empty_base_classes
+)
+{
+ if (clang_type && name && name[0])
+ {
+ QualType qual_type(QualType::getFromOpaquePtr(clang_type));
+ switch (qual_type->getTypeClass())
+ {
+ case Type::Record:
+ {
+ 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 && RecordHasFields(base_class_decl) == false)
+ continue;
+
+ if (base_class->getType().getAsString().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 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_context->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 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_context,
+// mem_ptr_type->getPointeeType().getAsOpaquePtr(),
+// name);
+// }
+// }
+// break;
+//
+ case Type::LValueReference:
+ case Type::RValueReference:
+ {
+ ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
+ QualType pointee_type = reference_type->getPointeeType();
+
+ if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
+ {
+ return GetIndexOfChildWithName (ast_context,
+ reference_type->getPointeeType().getAsOpaquePtr(),
+ name,
+ omit_empty_base_classes);
+ }
+ }
+ break;
+
+ case Type::Pointer:
+ {
+ PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr());
+ QualType pointee_type = pointer_type->getPointeeType();
+
+ if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
+ {
+ return GetIndexOfChildWithName (ast_context,
+ pointer_type->getPointeeType().getAsOpaquePtr(),
+ 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_context->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 Type::Typedef:
+ return GetIndexOfChildWithName (ast_context,
+ cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(),
+ name,
+ omit_empty_base_classes);
+
+ default:
+ break;
+ }
+ }
+ return UINT32_MAX;
+}
+
+#pragma mark TagType
+
+bool
+ClangASTContext::SetTagTypeKind (void *tag_clang_type, int kind)
+{
+ if (tag_clang_type)
+ {
+ QualType tag_qual_type(QualType::getFromOpaquePtr(tag_clang_type));
+ Type *clang_type = tag_qual_type.getTypePtr();
+ if (clang_type)
+ {
+ 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 DeclContext Functions
+
+DeclContext *
+ClangASTContext::GetDeclContextForType (void *clang_type)
+{
+ if (clang_type == NULL)
+ return NULL;
+
+ QualType qual_type(QualType::getFromOpaquePtr(clang_type));
+ switch (qual_type->getTypeClass())
+ {
+ case Type::FunctionNoProto: break;
+ case Type::FunctionProto: break;
+ case Type::IncompleteArray: break;
+ case Type::VariableArray: break;
+ case Type::ConstantArray: break;
+ case Type::ExtVector: break;
+ case Type::Vector: break;
+ case Type::Builtin: break;
+ case Type::ObjCObjectPointer: break;
+ case Type::BlockPointer: break;
+ case Type::Pointer: break;
+ case Type::LValueReference: break;
+ case Type::RValueReference: break;
+ case Type::MemberPointer: break;
+ case Type::Complex: break;
+ case Type::ObjCInterface: break;
+ case Type::Record:
+ return cast<RecordType>(qual_type)->getDecl();
+ case Type::Enum:
+ return cast<EnumType>(qual_type)->getDecl();
+ case Type::Typedef:
+ return ClangASTContext::GetDeclContextForType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr());
+
+ case Type::TypeOfExpr: break;
+ case Type::TypeOf: break;
+ case Type::Decltype: break;
+ //case Type::QualifiedName: break;
+ case Type::TemplateSpecialization: break;
+ }
+ // No DeclContext in this type...
+ return NULL;
+}
+
+#pragma mark Namespace Declarations
+
+NamespaceDecl *
+ClangASTContext::GetUniqueNamespaceDeclaration (const char *name, const Declaration &decl, DeclContext *decl_ctx)
+{
+ // TODO: Do something intelligent with the Declaration object passed in
+ // like maybe filling in the SourceLocation with it...
+ if (name)
+ {
+ ASTContext *ast_context = getASTContext();
+ if (decl_ctx == NULL)
+ decl_ctx = ast_context->getTranslationUnitDecl();
+ return NamespaceDecl::Create(*ast_context, decl_ctx, SourceLocation(), &ast_context->Idents.get(name));
+ }
+ return NULL;
+}
+
+
+#pragma mark Function Types
+
+FunctionDecl *
+ClangASTContext::CreateFunctionDeclaration (const char *name, void *function_clang_type, int storage, bool is_inline)
+{
+ if (name)
+ {
+ ASTContext *ast_context = getASTContext();
+ assert (ast_context != NULL);
+
+ if (name && name[0])
+ {
+ return FunctionDecl::Create(*ast_context,
+ ast_context->getTranslationUnitDecl(),
+ SourceLocation(),
+ DeclarationName (&ast_context->Idents.get(name)),
+ QualType::getFromOpaquePtr(function_clang_type),
+ NULL,
+ (FunctionDecl::StorageClass)storage,
+ (FunctionDecl::StorageClass)storage,
+ is_inline);
+ }
+ else
+ {
+ return FunctionDecl::Create(*ast_context,
+ ast_context->getTranslationUnitDecl(),
+ SourceLocation(),
+ DeclarationName (),
+ QualType::getFromOpaquePtr(function_clang_type),
+ NULL,
+ (FunctionDecl::StorageClass)storage,
+ (FunctionDecl::StorageClass)storage,
+ is_inline);
+ }
+ }
+ return NULL;
+}
+
+void *
+ClangASTContext::CreateFunctionType (void *result_type, void **args, unsigned num_args, bool isVariadic, unsigned TypeQuals)
+{
+ ASTContext *ast_context = getASTContext();
+ assert (ast_context != NULL);
+ std::vector<QualType> qual_type_args;
+ for (unsigned i=0; i<num_args; ++i)
+ qual_type_args.push_back (QualType::getFromOpaquePtr(args[i]));
+
+ // TODO: Detect calling convention in DWARF?
+ return ast_context->getFunctionType(QualType::getFromOpaquePtr(result_type),
+ qual_type_args.data(),
+ qual_type_args.size(),
+ isVariadic,
+ TypeQuals,
+ false, // hasExceptionSpec
+ false, // hasAnyExceptionSpec,
+ 0, // NumExs
+ 0, // const QualType *ExArray
+ FunctionType::ExtInfo ()).getAsOpaquePtr(); // NoReturn);
+}
+
+ParmVarDecl *
+ClangASTContext::CreateParmeterDeclaration (const char *name, void * return_type, int storage)
+{
+ ASTContext *ast_context = getASTContext();
+ assert (ast_context != NULL);
+ return ParmVarDecl::Create(*ast_context,
+ ast_context->getTranslationUnitDecl(),
+ SourceLocation(),
+ name && name[0] ? &ast_context->Idents.get(name) : NULL,
+ QualType::getFromOpaquePtr(return_type),
+ NULL,
+ (VarDecl::StorageClass)storage,
+ (VarDecl::StorageClass)storage,
+ 0);
+}
+
+void
+ClangASTContext::SetFunctionParameters (FunctionDecl *function_decl, ParmVarDecl **params, unsigned num_params)
+{
+ if (function_decl)
+ function_decl->setParams (params, num_params);
+}
+
+
+#pragma mark Array Types
+
+void *
+ClangASTContext::CreateArrayType (void *element_type, size_t element_count, uint32_t bit_stride)
+{
+ if (element_type)
+ {
+ ASTContext *ast_context = getASTContext();
+ assert (ast_context != NULL);
+ llvm::APInt ap_element_count (64, element_count);
+ return ast_context->getConstantArrayType(QualType::getFromOpaquePtr(element_type),
+ ap_element_count,
+ ArrayType::Normal,
+ 0).getAsOpaquePtr(); // ElemQuals
+ }
+ return NULL;
+}
+
+
+#pragma mark TagDecl
+
+bool
+ClangASTContext::StartTagDeclarationDefinition (void *clang_type)
+{
+ if (clang_type)
+ {
+ QualType qual_type (QualType::getFromOpaquePtr(clang_type));
+ Type *t = qual_type.getTypePtr();
+ if (t)
+ {
+ TagType *tag_type = dyn_cast<TagType>(t);
+ if (tag_type)
+ {
+ TagDecl *tag_decl = tag_type->getDecl();
+ if (tag_decl)
+ {
+ tag_decl->startDefinition();
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTContext::CompleteTagDeclarationDefinition (void *clang_type)
+{
+ if (clang_type)
+ {
+ QualType qual_type (QualType::getFromOpaquePtr(clang_type));
+ Type *t = qual_type.getTypePtr();
+ if (t)
+ {
+ TagType *tag_type = dyn_cast<TagType>(t);
+ if (tag_type)
+ {
+ TagDecl *tag_decl = tag_type->getDecl();
+ if (tag_decl)
+ {
+ tag_decl->completeDefinition();
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+#pragma mark Enumeration Types
+
+void *
+ClangASTContext::CreateEnumerationType (const Declaration &decl, const char *name)
+{
+ // TODO: Do something intelligent with the Declaration object passed in
+ // like maybe filling in the SourceLocation with it...
+ ASTContext *ast_context = getASTContext();
+ assert (ast_context != NULL);
+ EnumDecl *enum_decl = EnumDecl::Create(*ast_context,
+ ast_context->getTranslationUnitDecl(),
+ SourceLocation(),
+ name && name[0] ? &ast_context->Idents.get(name) : NULL,
+ SourceLocation(),
+ NULL);
+ if (enum_decl)
+ return ast_context->getTagDeclType(enum_decl).getAsOpaquePtr();
+ return NULL;
+}
+
+bool
+ClangASTContext::AddEnumerationValueToEnumerationType
+(
+ void *enum_clang_type,
+ void *enumerator_clang_type,
+ const Declaration &decl,
+ const char *name,
+ int64_t enum_value,
+ uint32_t enum_value_bit_size
+)
+{
+ if (enum_clang_type && enumerator_clang_type && name)
+ {
+ // TODO: Do something intelligent with the Declaration object passed in
+ // like maybe filling in the SourceLocation with it...
+ ASTContext *ast_context = getASTContext();
+ IdentifierTable *identifier_table = getIdentifierTable();
+
+ assert (ast_context != NULL);
+ assert (identifier_table != NULL);
+ QualType enum_qual_type (QualType::getFromOpaquePtr(enum_clang_type));
+
+ 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, false);
+ enum_llvm_apsint = enum_value;
+ EnumConstantDecl *enumerator_decl =
+ EnumConstantDecl::Create(*ast_context,
+ enum_type->getDecl(),
+ SourceLocation(),
+ name ? &identifier_table->get(name) : NULL, // Identifier
+ QualType::getFromOpaquePtr(enumerator_clang_type),
+ NULL,
+ enum_llvm_apsint);
+
+ if (enumerator_decl)
+ {
+ enum_type->getDecl()->addDecl(enumerator_decl);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+#pragma mark Pointers & References
+
+void *
+ClangASTContext::CreatePointerType (void *clang_type)
+{
+ if (clang_type)
+ return getASTContext()->getPointerType(QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr();
+ return NULL;
+}
+
+void *
+ClangASTContext::CreateLValueReferenceType (void *clang_type)
+{
+ if (clang_type)
+ return getASTContext()->getLValueReferenceType (QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr();
+ return NULL;
+}
+
+void *
+ClangASTContext::CreateRValueReferenceType (void *clang_type)
+{
+ if (clang_type)
+ return getASTContext()->getRValueReferenceType (QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr();
+ return NULL;
+}
+
+size_t
+ClangASTContext::GetPointerBitSize ()
+{
+ ASTContext *ast_context = getASTContext();
+ return ast_context->getTypeSize(ast_context->VoidPtrTy);
+}
+
+bool
+ClangASTContext::IsPointerOrReferenceType (void *clang_type, void **target_type)
+{
+ if (clang_type == NULL)
+ return false;
+
+ QualType qual_type (QualType::getFromOpaquePtr(clang_type));
+ switch (qual_type->getTypeClass())
+ {
+ case Type::ObjCObjectPointer:
+ if (target_type)
+ *target_type = cast<ObjCObjectPointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
+ return true;
+ case Type::BlockPointer:
+ if (target_type)
+ *target_type = cast<BlockPointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
+ return true;
+ case Type::Pointer:
+ if (target_type)
+ *target_type = cast<PointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
+ return true;
+ case Type::MemberPointer:
+ if (target_type)
+ *target_type = cast<MemberPointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
+ return true;
+ case Type::LValueReference:
+ if (target_type)
+ *target_type = cast<LValueReferenceType>(qual_type)->desugar().getAsOpaquePtr();
+ return true;
+ case Type::RValueReference:
+ if (target_type)
+ *target_type = cast<LValueReferenceType>(qual_type)->desugar().getAsOpaquePtr();
+ return true;
+ case Type::Typedef:
+ return ClangASTContext::IsPointerOrReferenceType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr());
+ default:
+ break;
+ }
+ return false;
+}
+
+size_t
+ClangASTContext::GetTypeBitSize (clang::ASTContext *ast_context, void *clang_type)
+{
+ if (clang_type)
+ return ast_context->getTypeSize(QualType::getFromOpaquePtr(clang_type));
+ return 0;
+}
+
+size_t
+ClangASTContext::GetTypeBitAlign (clang::ASTContext *ast_context, void *clang_type)
+{
+ if (clang_type)
+ return ast_context->getTypeAlign(QualType::getFromOpaquePtr(clang_type));
+ return 0;
+}
+
+bool
+ClangASTContext::IsIntegerType (void * clang_type, bool &is_signed)
+{
+ if (!clang_type)
+ return false;
+
+ QualType qual_type (QualType::getFromOpaquePtr(clang_type));
+ 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
+ClangASTContext::IsPointerType (void *clang_type, void **target_type)
+{
+ if (clang_type)
+ {
+ QualType qual_type (QualType::getFromOpaquePtr(clang_type));
+ switch (qual_type->getTypeClass())
+ {
+ case Type::ObjCObjectPointer:
+ if (target_type)
+ *target_type = cast<ObjCObjectPointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
+ return true;
+ case Type::BlockPointer:
+ if (target_type)
+ *target_type = cast<BlockPointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
+ return true;
+ case Type::Pointer:
+ if (target_type)
+ *target_type = cast<PointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
+ return true;
+ case Type::MemberPointer:
+ if (target_type)
+ *target_type = cast<MemberPointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
+ return true;
+ case Type::Typedef:
+ return ClangASTContext::IsPointerOrReferenceType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), target_type);
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTContext::IsFloatingPointType (void *clang_type, uint32_t &count, bool &is_complex)
+{
+ if (clang_type)
+ {
+ QualType qual_type (QualType::getFromOpaquePtr(clang_type));
+
+ 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 (IsFloatingPointType(CT->getElementType().getAsOpaquePtr(), count, is_complex))
+ {
+ count = 2;
+ is_complex = true;
+ return true;
+ }
+ }
+ else if (const VectorType *VT = dyn_cast<VectorType>(qual_type->getCanonicalTypeInternal()))
+ {
+ if (IsFloatingPointType(VT->getElementType().getAsOpaquePtr(), count, is_complex))
+ {
+ count = VT->getNumElements();
+ is_complex = false;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+bool
+ClangASTContext::IsCStringType (void *clang_type, uint32_t &length)
+{
+ if (clang_type)
+ {
+ QualType qual_type (QualType::getFromOpaquePtr(clang_type));
+ switch (qual_type->getTypeClass())
+ {
+ case Type::ConstantArray:
+ {
+ ConstantArrayType *array = cast<ConstantArrayType>(qual_type.getTypePtr());
+ QualType element_qual_type = array->getElementType();
+ Type *canonical_type = element_qual_type->getCanonicalTypeInternal().getTypePtr();
+ if (canonical_type && canonical_type->isCharType())
+ {
+ // We know the size of the array and it could be a C string
+ // since it is an array of characters
+ length = array->getSize().getLimitedValue();
+ return true;
+ }
+ }
+ break;
+
+ case Type::Pointer:
+ {
+ PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr());
+ Type *pointee_type_ptr = pointer_type->getPointeeType().getTypePtr();
+ if (pointee_type_ptr)
+ {
+ Type *canonical_type_ptr = pointee_type_ptr->getCanonicalTypeInternal().getTypePtr();
+ length = 0; // No length info, read until a NULL terminator is received
+ if (canonical_type_ptr)
+ return canonical_type_ptr->isCharType();
+ else
+ return pointee_type_ptr->isCharType();
+ }
+ }
+ break;
+
+ case Type::Typedef:
+ return ClangASTContext::IsCStringType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), length);
+
+ case Type::LValueReference:
+ case Type::RValueReference:
+ {
+ ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
+ Type *pointee_type_ptr = reference_type->getPointeeType().getTypePtr();
+ if (pointee_type_ptr)
+ {
+ Type *canonical_type_ptr = pointee_type_ptr->getCanonicalTypeInternal().getTypePtr();
+ length = 0; // No length info, read until a NULL terminator is received
+ if (canonical_type_ptr)
+ return canonical_type_ptr->isCharType();
+ else
+ return pointee_type_ptr->isCharType();
+ }
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTContext::IsArrayType (void * clang_type, void **member_type, uint64_t *size)
+{
+ if (!clang_type)
+ return false;
+
+ QualType qual_type (QualType::getFromOpaquePtr(clang_type));
+
+ switch (qual_type->getTypeClass())
+ {
+ case Type::ConstantArray:
+ if (member_type)
+ *member_type = cast<ConstantArrayType>(qual_type)->getElementType().getAsOpaquePtr();
+ if (size)
+ *size = cast<ConstantArrayType>(qual_type)->getSize().getLimitedValue(ULONG_LONG_MAX);
+ return true;
+ case Type::IncompleteArray:
+ if (member_type)
+ *member_type = cast<IncompleteArrayType>(qual_type)->getElementType().getAsOpaquePtr();
+ if (size)
+ *size = 0;
+ return true;
+ case Type::VariableArray:
+ if (member_type)
+ *member_type = cast<VariableArrayType>(qual_type)->getElementType().getAsOpaquePtr();
+ if (size)
+ *size = 0;
+ case Type::DependentSizedArray:
+ if (member_type)
+ *member_type = cast<DependentSizedArrayType>(qual_type)->getElementType().getAsOpaquePtr();
+ if (size)
+ *size = 0;
+ return true;
+ }
+ return false;
+}
+
+
+#pragma mark Typedefs
+
+void *
+ClangASTContext::CreateTypedefType (const char *name, void *clang_type, DeclContext *decl_ctx)
+{
+ if (clang_type)
+ {
+ QualType qual_type (QualType::getFromOpaquePtr(clang_type));
+ ASTContext *ast_context = getASTContext();
+ IdentifierTable *identifier_table = getIdentifierTable();
+ assert (ast_context != NULL);
+ assert (identifier_table != NULL);
+ if (decl_ctx == NULL)
+ decl_ctx = ast_context->getTranslationUnitDecl();
+ TypedefDecl *decl = TypedefDecl::Create(*ast_context,
+ decl_ctx,
+ SourceLocation(),
+ name ? &identifier_table->get(name) : NULL, // Identifier
+ ast_context->CreateTypeSourceInfo(qual_type));
+
+ // Get a uniqued QualType for the typedef decl type
+ return ast_context->getTypedefType (decl).getAsOpaquePtr();
+ }
+ return NULL;
+}
+
+
+std::string
+ClangASTContext::GetTypeName (void *opaque_qual_type)
+{
+ std::string return_name;
+
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(opaque_qual_type));
+
+ const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>();
+ if (typedef_type)
+ {
+ const clang::TypedefDecl *typedef_decl = typedef_type->getDecl();
+ return_name = typedef_decl->getQualifiedNameAsString();
+ }
+ else
+ {
+ return_name = qual_type.getAsString();
+ }
+
+ return return_name;
+}
+
+// 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_context, void *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;
+//}
+
+size_t
+ClangASTContext::ConvertStringToFloatValue (ASTContext *ast_context, void *clang_type, const char *s, uint8_t *dst, size_t dst_size)
+{
+ if (clang_type)
+ {
+ QualType qual_type (QualType::getFromOpaquePtr(clang_type));
+ uint32_t count = 0;
+ bool is_complex = false;
+ if (ClangASTContext::IsFloatingPointType (clang_type, count, is_complex))
+ {
+ // TODO: handle complex and vector types
+ if (count != 1)
+ return false;
+
+ StringRef s_sref(s);
+ APFloat ap_float(ast_context->getFloatTypeSemantics(qual_type), s_sref);
+
+ const uint64_t bit_size = ast_context->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;
+}
diff --git a/lldb/source/Symbol/CompileUnit.cpp b/lldb/source/Symbol/CompileUnit.cpp
new file mode 100644
index 00000000000..60a893b1d1e
--- /dev/null
+++ b/lldb/source/Symbol/CompileUnit.cpp
@@ -0,0 +1,366 @@
+//===-- 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/Symbol/LineTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CompileUnit::CompileUnit (Module *module, void *user_data, const char *pathname, const lldb::user_id_t cu_sym_id, Language::Type language) :
+ ModuleChild(module),
+ FileSpec (pathname),
+ UserID(cu_sym_id),
+ Language (language),
+ m_user_data (user_data),
+ m_flags (0),
+ m_functions (),
+ m_support_files (),
+ m_line_table_ap (),
+ m_variables()
+{
+ assert(module != NULL);
+}
+
+CompileUnit::CompileUnit (Module *module, void *user_data, const FileSpec &fspec, const lldb::user_id_t cu_sym_id, Language::Type language) :
+ ModuleChild(module),
+ FileSpec (fspec),
+ UserID(cu_sym_id),
+ Language (language),
+ m_user_data (user_data),
+ m_flags (0),
+ m_functions (),
+ m_support_files (),
+ m_line_table_ap (),
+ m_variables()
+{
+ assert(module != NULL);
+}
+
+CompileUnit::~CompileUnit ()
+{
+}
+
+void
+CompileUnit::CalculateSymbolContext(SymbolContext* sc)
+{
+ sc->comp_unit = this;
+ GetModule()->CalculateSymbolContext(sc);
+}
+
+void
+CompileUnit::DumpSymbolContext(Stream *s)
+{
+ GetModule()->DumpSymbolContext(s);
+ s->Printf(", CompileUnit{0x%8.8x}", GetID());
+}
+
+
+
+//----------------------------------------------------------------------
+// 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: ", (int)sizeof(void*) * 2, 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;
+}
+
+
+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, LineEntry *line_entry_ptr)
+{
+ uint32_t file_idx = 0;
+
+ if (file_spec_ptr)
+ {
+ file_idx = GetSupportFiles().FindFileIndex (1, *file_spec_ptr);
+ 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();
+ file_idx = support_files.FindFileIndex (1, support_files.GetFileSpecAtIndex(0));
+ if (file_idx == UINT32_MAX)
+ file_idx = 0;
+ }
+ LineTable *line_table = GetLineTable();
+ if (line_table)
+ return line_table->FindLineEntryIndexByFileIndex (start_idx, file_idx, line, true, 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
+)
+{
+ const uint32_t prev_size = sc_list.GetSize();
+ bool file_spec_matches_cu_file_spec = FileSpec::Compare(file_spec, this, !file_spec.GetDirectory().IsEmpty()) == 0;
+ if (check_inlines || file_spec_matches_cu_file_spec)
+ {
+ SymbolContext sc(GetModule());
+ sc.comp_unit = this;
+
+ 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);
+ if (file_idx == UINT32_MAX)
+ return 0;
+ }
+
+ if (line != 0)
+ {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+
+ if (line_table != NULL)
+ {
+ // 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);
+
+ if (file_idx != UINT32_MAX)
+ {
+ uint32_t found_line;
+
+ uint32_t line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_idx, line, exact, &sc.line_entry);
+ found_line = sc.line_entry.line;
+
+ while (line_idx != UINT_MAX)
+ {
+ 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);
+ }
+
+ }
+ 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/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
new file mode 100644
index 00000000000..febca924137
--- /dev/null
+++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -0,0 +1,1344 @@
+//===-- 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>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static void
+DumpRegisterName (Stream *s, Thread *thread, const ArchSpec *arch, uint32_t reg_kind, uint32_t reg_num)
+{
+ const char *reg_name = NULL;
+ RegisterContext *reg_ctx = NULL;
+ if (thread)
+ {
+ reg_ctx = thread->GetRegisterContext();
+ if (reg_ctx)
+ reg_name = reg_ctx->GetRegisterName (reg_ctx->ConvertRegisterKindToRegisterNumber (reg_kind, reg_num));
+ }
+
+ if (reg_name == NULL && arch != NULL)
+ {
+ switch (reg_kind)
+ {
+ case eRegisterKindDWARF: reg_name = arch->GetRegisterName(reg_num, eRegisterKindDWARF); break;
+ case eRegisterKindGCC: reg_name = arch->GetRegisterName(reg_num, eRegisterKindGCC); break;
+ default:
+ break;
+ }
+ }
+
+ if (reg_name)
+ s->PutCString(reg_name);
+ else
+ {
+ const char *reg_kind_name = NULL;
+ switch (reg_kind)
+ {
+ case eRegisterKindDWARF: reg_kind_name = "dwarf-reg"; break;
+ case eRegisterKindGCC: reg_kind_name = "compiler-reg"; break;
+ case eRegisterKindGeneric: reg_kind_name = "generic-reg"; break;
+ default:
+ break;
+ }
+ if (reg_kind_name)
+ s->Printf("%s(%u)", reg_kind_name, reg_num);
+ else
+ s->Printf("reg(%d.%u)", reg_kind, reg_num);
+ }
+}
+
+
+#pragma mark DWARFCallFrameInfo::RegisterLocation
+
+DWARFCallFrameInfo::RegisterLocation::RegisterLocation() :
+ m_type(isSame)
+{
+}
+
+
+bool
+DWARFCallFrameInfo::RegisterLocation::operator == (const DWARFCallFrameInfo::RegisterLocation& rhs) const
+{
+ if (m_type != rhs.m_type)
+ return false;
+ switch (m_type)
+ {
+ case unspecified:
+ case isUndefined:
+ case isSame:
+ return true;
+
+ case atCFAPlusOffset:
+ return m_location.offset == rhs.m_location.offset;
+
+ case isCFAPlusOffset:
+ return m_location.offset == rhs.m_location.offset;
+
+ case inOtherRegister:
+ return m_location.reg_num == rhs.m_location.reg_num;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+void
+DWARFCallFrameInfo::RegisterLocation::SetUnspecified()
+{
+ m_type = unspecified;
+}
+
+void
+DWARFCallFrameInfo::RegisterLocation::SetUndefined()
+{
+ m_type = isUndefined;
+}
+
+void
+DWARFCallFrameInfo::RegisterLocation::SetSame()
+{
+ m_type = isSame;
+}
+
+void
+DWARFCallFrameInfo::RegisterLocation::SetAtCFAPlusOffset(int64_t offset)
+{
+ m_type = atCFAPlusOffset;
+ m_location.offset = offset;
+}
+
+void
+DWARFCallFrameInfo::RegisterLocation::SetIsCFAPlusOffset(int64_t offset)
+{
+ m_type = isCFAPlusOffset;
+ m_location.offset = offset;
+}
+
+void
+DWARFCallFrameInfo::RegisterLocation::SetInRegister (uint32_t reg_num)
+{
+ m_type = inOtherRegister;
+ m_location.reg_num = reg_num;
+}
+
+void
+DWARFCallFrameInfo::RegisterLocation::SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len)
+{
+ m_type = atDWARFExpression;
+ m_location.expr.opcodes = opcodes;
+ m_location.expr.length = len;
+}
+
+void
+DWARFCallFrameInfo::RegisterLocation::SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len)
+{
+ m_type = isDWARFExpression;
+ m_location.expr.opcodes = opcodes;
+ m_location.expr.length = len;
+}
+
+void
+DWARFCallFrameInfo::RegisterLocation::Dump(Stream *s, const DWARFCallFrameInfo &cfi, Thread *thread, const Row *row, uint32_t reg_num) const
+{
+ const ArchSpec *arch = cfi.GetArchitecture();
+ const uint32_t reg_kind = cfi.GetRegisterKind();
+
+ DumpRegisterName (s, thread, arch, reg_kind, reg_num);
+ s->PutChar('=');
+
+ switch (m_type)
+ {
+ case unspecified:
+ s->PutChar('?');
+ break;
+
+ case isUndefined:
+ s->PutCString("undefined");
+ break;
+
+ case isSame:
+ s->PutCString("same");
+ break;
+
+ case atCFAPlusOffset:
+ s->PutChar('[');
+ // Fall through to isCFAPlusOffset...
+ case isCFAPlusOffset:
+ {
+ DumpRegisterName (s, thread, arch, reg_kind, row->GetCFARegister());
+ int32_t offset = row->GetCFAOffset() + m_location.offset;
+ if (offset != 0)
+ s->Printf("%-+d", offset);
+ if (m_type == atCFAPlusOffset)
+ s->PutChar(']');
+ }
+ break;
+
+ case inOtherRegister:
+ DumpRegisterName (s, thread, arch, reg_kind, m_location.reg_num);
+ break;
+
+ case atDWARFExpression:
+ s->PutCString("[EXPR] ");
+ break;
+
+ case isDWARFExpression:
+ s->PutCString("EXPR ");
+ break;
+ }
+}
+
+
+#pragma mark DWARFCallFrameInfo::Row
+
+DWARFCallFrameInfo::Row::Row() :
+ m_offset(0),
+ m_cfa_reg_num(0),
+ m_cfa_offset(0),
+ m_register_locations()
+{
+}
+
+DWARFCallFrameInfo::Row::~Row()
+{
+}
+
+void
+DWARFCallFrameInfo::Row::Clear()
+{
+ m_register_locations.clear();
+}
+bool
+DWARFCallFrameInfo::Row::GetRegisterInfo (uint32_t reg_num, DWARFCallFrameInfo::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
+DWARFCallFrameInfo::Row::SetRegisterInfo (uint32_t reg_num, const RegisterLocation& register_location)
+{
+ m_register_locations[reg_num] = register_location;
+}
+
+
+void
+DWARFCallFrameInfo::Row::Dump(Stream* s, const DWARFCallFrameInfo &cfi, Thread *thread, lldb::addr_t base_addr) const
+{
+ const ArchSpec *arch = cfi.GetArchitecture();
+ const uint32_t reg_kind = cfi.GetRegisterKind();
+ collection::const_iterator pos, end = m_register_locations.end();
+ s->Indent();
+ s->Printf("0x%16.16llx: CFA=", m_offset + base_addr);
+ DumpRegisterName(s, thread, arch, reg_kind, m_cfa_reg_num);
+ if (m_cfa_offset != 0)
+ s->Printf("%-+lld", m_cfa_offset);
+
+ for (pos = m_register_locations.begin(); pos != end; ++pos)
+ {
+ s->PutChar(' ');
+ pos->second.Dump(s, cfi, thread, this, pos->first);
+ }
+ s->EOL();
+}
+
+
+#pragma mark DWARFCallFrameInfo::FDE
+
+
+DWARFCallFrameInfo::FDE::FDE (dw_offset_t offset, const AddressRange &range) :
+ m_fde_offset (offset),
+ m_range (range),
+ m_row_list ()
+{
+}
+
+DWARFCallFrameInfo::FDE::~FDE()
+{
+}
+
+void
+DWARFCallFrameInfo::FDE::AppendRow (const Row &row)
+{
+ if (m_row_list.empty() || m_row_list.back().GetOffset() != row.GetOffset())
+ m_row_list.push_back(row);
+ else
+ m_row_list.back() = row;
+}
+
+void
+DWARFCallFrameInfo::FDE::Dump (Stream *s, const DWARFCallFrameInfo &cfi, Thread* thread) const
+{
+ s->Indent();
+ s->Printf("FDE{0x%8.8x} ", m_fde_offset);
+ m_range.Dump(s, NULL, Address::DumpStyleFileAddress);
+ lldb::addr_t fde_base_addr = m_range.GetBaseAddress().GetFileAddress();
+ s->EOL();
+ s->IndentMore();
+ collection::const_iterator pos, end = m_row_list.end();
+ for (pos = m_row_list.begin(); pos != end; ++pos)
+ {
+ pos->Dump(s, cfi, thread, fde_base_addr);
+ }
+ s->IndentLess();
+}
+
+const AddressRange &
+DWARFCallFrameInfo::FDE::GetAddressRange() const
+{
+ return m_range;
+}
+
+bool
+DWARFCallFrameInfo::FDE::IsValidRowIndex (uint32_t idx) const
+{
+ return idx < m_row_list.size();
+}
+
+const DWARFCallFrameInfo::Row&
+DWARFCallFrameInfo::FDE::GetRowAtIndex (uint32_t idx)
+{
+ // You must call IsValidRowIndex(idx) first before calling this!!!
+ return m_row_list[idx];
+}
+#pragma mark DWARFCallFrameInfo::FDEInfo
+
+DWARFCallFrameInfo::FDEInfo::FDEInfo () :
+ fde_offset (0),
+ fde_sp()
+{
+}
+
+DWARFCallFrameInfo::FDEInfo::FDEInfo (off_t offset) :
+ fde_offset(offset),
+ fde_sp()
+{
+}
+
+#pragma mark DWARFCallFrameInfo::CIE
+
+DWARFCallFrameInfo::CIE::CIE(dw_offset_t offset) :
+ cie_offset (offset),
+ version (0),
+ augmentation(),
+ code_align (0),
+ data_align (0),
+ return_addr_reg_num (0),
+ inst_offset (0),
+ inst_length (0),
+ ptr_encoding (DW_GNU_EH_PE_absptr)
+{
+}
+
+
+DWARFCallFrameInfo::CIE::~CIE()
+{
+}
+
+void
+DWARFCallFrameInfo::CIE::Dump(Stream *s, Thread* thread, const ArchSpec *arch, uint32_t reg_kind) const
+{
+ s->Indent();
+ s->Printf("CIE{0x%8.8x} version=%u, code_align=%u, data_align=%d, return_addr_reg=", cie_offset, version, code_align, data_align);
+ DumpRegisterName(s, thread, arch, reg_kind, return_addr_reg_num);
+ s->Printf(", instr_offset=0x%8.8x, instr_length=%u, ptr_encoding=0x%02x\n",
+ inst_offset,
+ inst_length,
+ ptr_encoding);
+}
+
+#pragma mark DWARFCallFrameInfo::CIE
+
+DWARFCallFrameInfo::DWARFCallFrameInfo(ObjectFile *objfile, Section *section, uint32_t reg_kind) :
+ m_objfile (objfile),
+ m_section (section),
+ m_reg_kind (reg_kind), // The flavor of registers that the CFI data uses (One of the defines that starts with "LLDB_REGKIND_")
+ m_cfi_data (),
+ m_cie_map (),
+ m_fde_map ()
+{
+ if (objfile && section)
+ {
+ section->ReadSectionDataFromObjectFile (objfile, m_cfi_data);
+ }
+}
+
+DWARFCallFrameInfo::~DWARFCallFrameInfo()
+{
+}
+
+bool
+DWARFCallFrameInfo::IsEHFrame() const
+{
+ return (m_reg_kind == eRegisterKindGCC);
+}
+
+const ArchSpec *
+DWARFCallFrameInfo::GetArchitecture() const
+{
+ if (m_objfile && m_objfile->GetModule())
+ return &m_objfile->GetModule()->GetArchitecture();
+ return NULL;
+}
+
+uint32_t
+DWARFCallFrameInfo::GetRegisterKind () const
+{
+ return m_reg_kind;
+}
+
+void
+DWARFCallFrameInfo::SetRegisterKind (uint32_t reg_kind)
+{
+ m_reg_kind = reg_kind;
+}
+
+
+
+
+const DWARFCallFrameInfo::CIE*
+DWARFCallFrameInfo::GetCIE(dw_offset_t cie_offset)
+{
+ Index ();
+
+ 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::CIE::shared_ptr
+DWARFCallFrameInfo::ParseCIE (const dw_offset_t cie_offset)
+{
+ CIE::shared_ptr cie_sp(new CIE(cie_offset));
+ const bool for_eh_frame = IsEHFrame();
+ dw_offset_t offset = cie_offset;
+ 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 && (!for_eh_frame && cie_id == 0xfffffffful) || (for_eh_frame && cie_id == 0ul))
+ {
+ size_t i;
+ // cie.offset = cie_offset;
+ // cie.length = length;
+ // cie.cieID = cieID;
+ cie_sp->ptr_encoding = DW_GNU_EH_PE_absptr;
+ 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')
+ {
+ fprintf(stderr, "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.
+ 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;
+ }
+ }
+
+ return cie_sp;
+}
+
+DWARFCallFrameInfo::FDE::shared_ptr
+DWARFCallFrameInfo::ParseFDE(const dw_offset_t fde_offset)
+{
+ const bool for_eh_frame = IsEHFrame();
+ FDE::shared_ptr fde_sp;
+
+ dw_offset_t offset = fde_offset;
+ const uint32_t length = m_cfi_data.GetU32(&offset);
+ dw_offset_t cie_offset = m_cfi_data.GetU32(&offset);
+ const dw_offset_t end_offset = fde_offset + length + 4;
+
+ // Translate the CIE_id from the eh_frame format, which
+ // is relative to the FDE offset, into a __eh_frame section
+ // offset
+ if (for_eh_frame)
+ cie_offset = offset - (cie_offset + 4);
+
+ const CIE* cie = GetCIE(cie_offset);
+ if (cie)
+ {
+ const lldb::addr_t pc_rel_addr = m_section->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_GNU_EH_PE_MASK_ENCODING, pc_rel_addr, text_addr, data_addr);
+
+ if (cie->augmentation[0] == 'z')
+ {
+ uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ offset += aug_data_len;
+ }
+
+ AddressRange fde_range (range_base, range_len, m_objfile->GetSectionList ());
+ fde_sp.reset(new FDE(fde_offset, fde_range));
+ if (offset < end_offset)
+ {
+ dw_offset_t fde_instr_offset = offset;
+ uint32_t fde_instr_length = end_offset - offset;
+ if (cie->inst_length > 0)
+ ParseInstructions(cie, fde_sp.get(), cie->inst_offset, cie->inst_length);
+ ParseInstructions(cie, fde_sp.get(), fde_instr_offset, fde_instr_length);
+ }
+ }
+ return fde_sp;
+}
+
+const DWARFCallFrameInfo::FDE *
+DWARFCallFrameInfo::FindFDE(const Address &addr)
+{
+ Index ();
+
+ VMRange find_range(addr.GetFileAddress(), 0);
+ fde_map_t::iterator pos = m_fde_map.lower_bound (find_range);
+ fde_map_t::iterator end = m_fde_map.end();
+
+ if (pos != end)
+ {
+ if (pos->first.Contains(find_range.GetBaseAddress()))
+ {
+ // Parse and cache the FDE if we already haven't
+ if (pos->second.fde_sp.get() == NULL)
+ pos->second.fde_sp = ParseFDE(pos->second.fde_offset);
+
+ return pos->second.fde_sp.get();
+ }
+ }
+ return NULL;
+}
+
+
+void
+DWARFCallFrameInfo::Index ()
+{
+ if (m_flags.IsClear(eFlagParsedIndex))
+ {
+ m_flags.Set (eFlagParsedIndex);
+ const bool for_eh_frame = IsEHFrame();
+ CIE::shared_ptr empty_cie_sp;
+ dw_offset_t offset = 0;
+ // Parse all of the CIEs first since we will need them to be able to
+ // properly parse the FDE addresses due to them possibly having
+ // GNU pointer encodings in their augmentations...
+ while (m_cfi_data.ValidOffsetForDataOfSize(offset, 8))
+ {
+ const dw_offset_t curr_offset = offset;
+ const uint32_t length = m_cfi_data.GetU32(&offset);
+ const dw_offset_t next_offset = offset + length;
+ const dw_offset_t cie_id = m_cfi_data.GetU32(&offset);
+
+ bool is_cie = for_eh_frame ? cie_id == 0 : cie_id == UINT32_MAX;
+ if (is_cie)
+ m_cie_map[curr_offset]= ParseCIE(curr_offset);
+
+ offset = next_offset;
+ }
+
+ // Now go back through and index all FDEs
+ offset = 0;
+ const lldb::addr_t pc_rel_addr = m_section->GetFileAddress();
+ const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;
+ const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;
+ while (m_cfi_data.ValidOffsetForDataOfSize(offset, 8))
+ {
+ const dw_offset_t curr_offset = offset;
+ const uint32_t length = m_cfi_data.GetU32(&offset);
+ const dw_offset_t next_offset = offset + length;
+ const dw_offset_t cie_id = m_cfi_data.GetU32(&offset);
+
+ bool is_fde = for_eh_frame ? cie_id != 0 : cie_id != UINT32_MAX;
+ if (is_fde)
+ {
+ dw_offset_t cie_offset;
+ if (for_eh_frame)
+ cie_offset = offset - (cie_id + 4);
+ else
+ cie_offset = cie_id;
+
+ const CIE* cie = GetCIE(cie_offset);
+ assert(cie);
+ 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_GNU_EH_PE_MASK_ENCODING, pc_rel_addr, text_addr, data_addr);
+ m_fde_map[VMRange(addr, addr + length)] = FDEInfo(curr_offset);
+ }
+
+ offset = next_offset;
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// Parse instructions for a FDE. The initial instruction for the CIE
+// are parsed first, then the instructions for the FDE are parsed
+//----------------------------------------------------------------------
+void
+DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t instr_offset, uint32_t instr_length)
+{
+ if (cie != NULL && fde == NULL)
+ return;
+
+ uint32_t reg_num = 0;
+ int32_t op_offset = 0;
+ uint32_t tmp_uval32;
+ uint32_t code_align = cie->code_align;
+ int32_t data_align = cie->data_align;
+ typedef std::list<Row> RowStack;
+
+ RowStack row_stack;
+ Row row;
+ if (fde->IsValidRowIndex(0))
+ row = fde->GetRowAtIndex(0);
+
+ dw_offset_t offset = instr_offset;
+ const dw_offset_t end_offset = instr_offset + instr_length;
+ 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.
+ fde->AppendRow(row);
+ 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 registe index
+
+ if (fde->IsValidRowIndex(0) && fde->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.
+ fde->AppendRow(row);
+ row.SetOffset(m_cfi_data.GetPointer(&offset) - fde->GetAddressRange().GetBaseAddress().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.
+ fde->AppendRow(row);
+ 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.
+ fde->AppendRow(row);
+ 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.
+ fde->AppendRow(row);
+ 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 (fde->IsValidRowIndex(0) && fde->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.)
+ row_stack.push_back(row);
+ 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 = row_stack.back();
+ row_stack.pop_back();
+ }
+ 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:
+ tmp_uval32 = extended_opcode;
+ break;
+ }
+ }
+ }
+ fde->AppendRow(row);
+}
+
+void
+DWARFCallFrameInfo::ParseAll()
+{
+ Index();
+ fde_map_t::iterator pos, end = m_fde_map.end();
+ for (pos = m_fde_map.begin(); pos != end; ++ pos)
+ {
+ if (pos->second.fde_sp.get() == NULL)
+ pos->second.fde_sp = ParseFDE(pos->second.fde_offset);
+ }
+}
+
+
+//bool
+//DWARFCallFrameInfo::UnwindRegisterAtIndex
+//(
+// const uint32_t reg_idx,
+// const Thread* currState,
+// const DWARFCallFrameInfo::Row* row,
+// mapped_memory_t * memCache,
+// Thread* unwindState
+//)
+//{
+// bool get_reg_success = false;
+//
+// const RegLocation* regLocation = row->regs.GetRegisterInfo(reg_idx);
+//
+// // On some systems, we may not get unwind info for the program counter,
+// // but the return address register can be used to get that information.
+// if (reg_idx == currState->GetPCRegNum(Thread::Index))
+// {
+// const RegLocation* returnAddrRegLocation = row->regs.GetRegisterInfo(currState->GetRARegNum(Thread::Index));
+// if (regLocation == NULL)
+// {
+// // We have nothing to the program counter, so lets see if this
+// // thread state has a return address (link register) that can
+// // help us track down the previous PC
+// regLocation = returnAddrRegLocation;
+// }
+// else if (regLocation->type == RegLocation::unspecified)
+// {
+// // We did have a location that didn't specify a value for unwinding
+// // the PC, so if there is a info for the return return address
+// // register (link register) lets use that
+// if (returnAddrRegLocation)
+// regLocation = returnAddrRegLocation;
+// }
+// }
+//
+// if (regLocation)
+// {
+// mach_vm_address_t unwoundRegValue = INVALID_VMADDR;
+// switch (regLocation->type)
+// {
+// case RegLocation::undefined:
+// // Register is not available, mark it as invalid
+// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false);
+// return true;
+//
+// case RegLocation::unspecified:
+// // Nothing to do if it is the same
+// return true;
+//
+// case RegLocation::same:
+// // Nothing to do if it is the same
+// return true;
+//
+// case RegLocation::atFPPlusOffset:
+// case RegLocation::isFPPlusOffset:
+// {
+// uint64_t unwindAddress = currState->GetRegisterValue(row->cfa_register, Thread::GCC, INVALID_VMADDR, &get_reg_success);
+//
+// if (get_reg_success)
+// {
+// unwindAddress += row->cfa_offset + regLocation->location.offset;
+//
+// if (regLocation->type == RegLocation::isFPPlusOffset)
+// {
+// unwindState->SetRegisterValue(reg_idx, Thread::Index, unwindAddress);
+// return true;
+// }
+// else
+// {
+// kern_return_t err = mapped_memory_read_pointer(memCache, unwindAddress, &unwoundRegValue);
+// if (err != KERN_SUCCESS)
+// {
+// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false);
+// return false;
+// }
+// unwindState->SetRegisterValue(reg_idx, Thread::Index, unwoundRegValue);
+// return true;
+// }
+// }
+// else
+// {
+// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false);
+// }
+// return false;
+// }
+// break;
+//
+// case RegLocation::atDWARFExpression:
+// case RegLocation::isDWARFExpression:
+// {
+// bool swap = false;
+// DWARFExpressionBaton baton = { currState, memCache, swap };
+// uint64_t expr_result = 0;
+// CSBinaryDataRef opcodes(regLocation->location.expr.opcodes, regLocation->location.expr.length, swap);
+// opcodes.SetPointerSize(currState->Is64Bit() ? 8 : 4);
+// const char * expr_err = CSDWARFExpression::Evaluate(DWARFExpressionReadMemoryDCScriptInterpreter::Type,
+// DWARFExpressionReadRegisterDCScriptInterpreter::Type,
+// &baton,
+// opcodes,
+// 0,
+// regLocation->location.expr.length,
+// NULL,
+// expr_result);
+// if (expr_err == NULL)
+// {
+// // SUCCESS!
+// if (regLocation->type == RegLocation::isDWARFExpression)
+// {
+// unwindState->SetRegisterValue(reg_idx, Thread::Index, expr_result);
+// return true;
+// }
+// else
+// {
+// kern_return_t err = mapped_memory_read_pointer(memCache, expr_result, &unwoundRegValue);
+// if (err != KERN_SUCCESS)
+// {
+// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false);
+// return false;
+// }
+// unwindState->SetRegisterValue(reg_idx, Thread::Index, unwoundRegValue);
+// return true;
+// }
+// }
+// else
+// {
+// // FAIL
+// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false);
+// }
+// return false;
+// }
+// break;
+//
+//
+// case RegLocation::inRegister:
+// // The value is in another register.
+// unwoundRegValue = currState->GetRegisterValue(regLocation->location.reg, Thread::GCC, 0, &get_reg_success);
+// if (get_reg_success)
+// {
+// unwindState->SetRegisterValue(reg_idx, Thread::Index, unwoundRegValue);
+// return true;
+// }
+// return false;
+//
+// default:
+// break;
+// }
+// }
+//
+// if (reg_idx == currState->GetSPRegNum(Thread::Index))
+// {
+// uint64_t cfa = currState->GetRegisterValue(row->cfa_register, Thread::GCC, 0, &get_reg_success);
+// if (get_reg_success)
+// {
+// return unwindState->SetSP(cfa + row->cfa_offset);
+// }
+// else
+// {
+// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false);
+// return false;
+// }
+// }
+//
+// return false;
+//}
+
+void
+DWARFCallFrameInfo::Dump(Stream *s, Thread *thread) const
+{
+ s->Indent();
+ s->Printf("DWARFCallFrameInfo for ");
+ *s << m_objfile->GetFileSpec();
+ if (m_flags.IsSet(eFlagParsedIndex))
+ {
+ s->Printf(" (CIE[%zu], FDE[%zu])\n", m_cie_map.size(), m_fde_map.size());
+ s->IndentMore();
+ cie_map_t::const_iterator cie_pos, cie_end = m_cie_map.end();
+ const ArchSpec *arch = &m_objfile->GetModule()->GetArchitecture();
+
+ for (cie_pos = m_cie_map.begin(); cie_pos != cie_end; ++ cie_pos)
+ {
+ if (cie_pos->second.get() == NULL)
+ {
+ s->Indent();
+ s->Printf("CIE{0x%8.8x} - unparsed\n", cie_pos->first);
+ }
+ else
+ {
+ cie_pos->second->Dump(s, thread, arch, m_reg_kind);
+ }
+ }
+
+ fde_map_t::const_iterator fde_pos, fde_end = m_fde_map.end();
+ for (fde_pos = m_fde_map.begin(); fde_pos != fde_end; ++ fde_pos)
+ {
+ if (fde_pos->second.fde_sp.get() == NULL)
+ {
+ s->Indent();
+ s->Printf("FDE{0x%8.8x} - unparsed\n", fde_pos->second.fde_offset);
+ }
+ else
+ {
+ fde_pos->second.fde_sp->Dump(s, *this, thread);
+ }
+ }
+ s->IndentLess();
+ }
+ else
+ {
+ s->PutCString(" (not indexed yet)\n");
+ }
+}
+
+
+//uint32_t
+//DWARFCallFrameInfo::UnwindThreadState(const Thread* currState, mapped_memory_t *memCache, bool is_first_frame, Thread* unwindState)
+//{
+// if (currState == NULL || unwindState == NULL)
+// return 0;
+//
+// *unwindState = *currState;
+// uint32_t numRegisterUnwound = 0;
+// uint64_t currPC = currState->GetPC(INVALID_VMADDR);
+//
+// if (currPC != INVALID_VMADDR)
+// {
+// // If this is not the first frame, we care about the previous instruction
+// // since it will be at the instruction following the instruction that
+// // made the function call.
+// uint64_t unwindPC = currPC;
+// if (unwindPC > 0 && !is_first_frame)
+// --unwindPC;
+//
+//#if defined(__i386__) || defined(__x86_64__)
+// // Only on i386 do we have __IMPORT segments that contain trampolines
+// if (!currState->Is64Bit() && ImportRangesContainsAddress(unwindPC))
+// {
+// uint64_t curr_sp = currState->GetSP(INVALID_VMADDR);
+// mach_vm_address_t pc = INVALID_VMADDR;
+// unwindState->SetSP(curr_sp + 4);
+// kern_return_t err = mapped_memory_read_pointer(memCache, curr_sp, &pc);
+// if (err == KERN_SUCCESS)
+// {
+// unwindState->SetPC(pc);
+// return 2;
+// }
+// }
+//#endif
+// FDE *fde = FindFDE(unwindPC);
+// if (fde)
+// {
+// FindRowUserData rowUserData (currState, unwindPC);
+// ParseInstructions (currState, fde, FindRowForAddress, &rowUserData);
+//
+// const uint32_t numRegs = currState->NumRegisters();
+// for (uint32_t regNum = 0; regNum < numRegs; regNum++)
+// {
+// if (UnwindRegisterAtIndex(regNum, currState, &rowUserData.state, memCache, unwindState))
+// numRegisterUnwound++;
+// }
+// }
+// }
+// return numRegisterUnwound;
+//}
+
+
diff --git a/lldb/source/Symbol/Declaration.cpp b/lldb/source/Symbol/Declaration.cpp
new file mode 100644
index 00000000000..a31a304b06f
--- /dev/null
+++ b/lldb/source/Symbol/Declaration.cpp
@@ -0,0 +1,172 @@
+//===-- 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;
+
+Declaration::Declaration() :
+ m_file(),
+ m_line(0),
+ m_column(0)
+{
+}
+
+Declaration::Declaration(const FileSpec& f, uint32_t l, uint32_t c) :
+ m_file(f),
+ m_line(l),
+ m_column(c)
+{
+}
+
+Declaration::Declaration(const Declaration& rhs) :
+ m_file(rhs.m_file),
+ m_line(rhs.m_line),
+ m_column(rhs.m_column)
+{
+}
+
+Declaration::Declaration(const Declaration* decl_ptr) :
+ m_file(),
+ m_line(0),
+ m_column(0)
+{
+ if (decl_ptr != NULL)
+ *this = *decl_ptr;
+}
+
+bool
+Declaration::IsValid() const
+{
+ return m_file && m_line != 0;
+}
+
+void
+Declaration::Clear()
+{
+ m_file.Clear();
+ m_line= 0;
+ m_column = 0;
+}
+
+void
+Declaration::Dump(Stream *s) const
+{
+ if (m_file)
+ {
+ *s << ", decl = '" << m_file;
+ if (m_line > 0)
+ s->Printf(":%u", m_line);
+ if (m_column > 0)
+ s->Printf(":%u", m_column);
+ s->PutChar('\'');
+ }
+ else
+ {
+ if (m_line > 0)
+ {
+ s->Printf(", line = %u", m_line);
+ if (m_column > 0)
+ s->Printf(":%u", m_column);
+ }
+ else if (m_column > 0)
+ s->Printf(", column = %u", m_column);
+ }
+}
+
+void
+Declaration::DumpStopContext (Stream *s) const
+{
+ if (m_file)
+ {
+ if (s->GetVerbose())
+ *s << m_file;
+ else
+ m_file.GetFilename().Dump(s);
+
+ if (m_line > 0)
+ s->Printf(":%u", m_line);
+ if (m_column > 0)
+ s->Printf(":%u", m_column);
+ }
+ else
+ {
+ s->Printf(" line %u", m_line);
+ if (m_column > 0)
+ s->Printf(":%u", m_column);
+ }
+}
+
+uint32_t
+Declaration::GetColumn() const
+{
+ return m_column;
+}
+
+FileSpec&
+Declaration::GetFile()
+{
+ return m_file;
+}
+
+const FileSpec&
+Declaration::GetFile() const
+{
+ return m_file;
+}
+
+uint32_t
+Declaration::GetLine() const
+{
+ return m_line;
+}
+
+size_t
+Declaration::MemorySize() const
+{
+ return sizeof(Declaration);
+}
+
+void
+Declaration::SetColumn(uint32_t col)
+{
+ m_column = col;
+}
+
+void
+Declaration::SetFile(const FileSpec& file)
+{
+ m_file = file;
+}
+
+void
+Declaration::SetLine(uint32_t line)
+{
+ m_line = line;
+}
+
+
+
+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;
+ if (a.m_column < b.m_column)
+ return -1;
+ else if (a.m_column > b.m_column)
+ return 1;
+ return 0;
+}
diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp
new file mode 100644
index 00000000000..51c449acd93
--- /dev/null
+++ b/lldb/source/Symbol/Function.cpp
@@ -0,0 +1,432 @@
+//===-- 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/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/CanonicalType.h"
+
+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) const
+{
+ if (m_name)
+ *s << ", name = \"" << m_name << "\"";
+ m_declaration.Dump(s);
+}
+
+
+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(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) const
+{
+ FunctionInfo::Dump(s);
+ 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());
+}
+
+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_blocks(this, range),
+ m_frame_base(),
+ m_flags(),
+ m_prologue_byte_size(0)
+{
+ 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(mangled, true),
+ m_blocks(this, range),
+ m_frame_base(),
+ m_flags(),
+ m_prologue_byte_size(0)
+{
+ assert(comp_unit != NULL);
+}
+
+
+Function::~Function()
+{
+}
+
+const AddressRange &
+Function::GetAddressRange()
+{
+ return GetBlocks(true).GetAddressRange();
+}
+
+BlockList &
+Function::GetBlocks(bool can_create)
+{
+ if (m_blocks.IsEmpty() && can_create)
+ {
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ assert(sc.module_sp);
+ sc.module_sp->GetSymbolVendor()->ParseFunctionBlocks(sc);
+ }
+ return m_blocks;
+}
+
+CompileUnit*
+Function::GetCompileUnit()
+{
+ return m_comp_unit;
+}
+
+const CompileUnit*
+Function::GetCompileUnit() const
+{
+ return m_comp_unit;
+}
+
+void
+Function::Dump(Stream *s, bool show_context) const
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ *s << "Function" << (const UserID&)*this;
+
+ m_mangled.Dump(s);
+
+// FunctionInfo::Dump(s);
+ if (m_type)
+ {
+ *s << ", type = " << (void*)m_type;
+ /// << " (";
+ ///m_type->DumpTypeName(s);
+ ///s->PutChar(')');
+ }
+ else if (m_type_uid != LLDB_INVALID_UID)
+ *s << ", type_uid = " << m_type_uid;
+
+ s->EOL();
+ // Dump the root object
+ if (!m_blocks.IsEmpty())
+ m_blocks.Dump(s, Block::RootID, INT_MAX, show_context);
+}
+
+
+void
+Function::CalculateSymbolContext(SymbolContext* sc)
+{
+ sc->function = this;
+ m_comp_unit->CalculateSymbolContext(sc);
+}
+
+void
+Function::DumpSymbolContext(Stream *s)
+{
+ m_comp_unit->DumpSymbolContext(s);
+ s->Printf(", Function{0x%8.8x}", GetID());
+}
+
+size_t
+Function::MemorySize () const
+{
+ size_t mem_size = sizeof(Function) + m_blocks.MemorySize();
+ return mem_size;
+}
+
+Type*
+Function::GetType()
+{
+ return m_type;
+}
+
+const Type*
+Function::GetType() const
+{
+ return m_type;
+}
+
+Type
+Function::GetReturnType ()
+{
+ clang::QualType clang_type (clang::QualType::getFromOpaquePtr(GetType()->GetOpaqueClangQualType()));
+ assert (clang_type->isFunctionType());
+ clang::FunctionType *function_type = dyn_cast<clang::FunctionType> (clang_type);
+ clang::QualType fun_return_qualtype = function_type->getResultType();
+
+ const ConstString fun_return_name(Type::GetClangTypeName(fun_return_qualtype.getAsOpaquePtr()));
+
+ SymbolContext sc;
+ CalculateSymbolContext (&sc);
+ // Null out everything below the CompUnit 'cause we don't actually know these.
+
+ size_t bit_size = ClangASTContext::GetTypeBitSize ((GetType()->GetClangASTContext().getASTContext()), &fun_return_qualtype);
+ Type return_type (0, GetType()->GetSymbolFile(), fun_return_name, bit_size, sc.comp_unit, 0, Type::eTypeUIDSynthetic, Declaration(), fun_return_qualtype.getAsOpaquePtr());
+ return return_type;
+}
+
+int
+Function::GetArgumentCount ()
+{
+ clang::QualType clang_type (clang::QualType::getFromOpaquePtr(GetType()->GetOpaqueClangQualType()));
+ assert (clang_type->isFunctionType());
+ if (!clang_type->isFunctionProtoType())
+ return -1;
+
+ const clang::FunctionProtoType *function_proto_type = dyn_cast<clang::FunctionProtoType>(clang_type);
+ if (function_proto_type != NULL)
+ return function_proto_type->getNumArgs();
+
+ return 0;
+}
+
+const Type
+Function::GetArgumentTypeAtIndex (size_t idx)
+{
+ clang::QualType clang_type (clang::QualType::getFromOpaquePtr(GetType()->GetOpaqueClangQualType()));
+ assert (clang_type->isFunctionType());
+ if (!clang_type->isFunctionProtoType())
+ return Type();
+
+ const clang::FunctionProtoType *function_proto_type = dyn_cast<clang::FunctionProtoType>(clang_type);
+ if (function_proto_type != NULL)
+ {
+ unsigned num_args = function_proto_type->getNumArgs();
+ if (idx >= num_args)
+ return Type();
+ clang::QualType arg_qualtype = (function_proto_type->arg_type_begin())[idx];
+
+ const ConstString arg_return_name(Type::GetClangTypeName(arg_qualtype.getAsOpaquePtr()));
+ SymbolContext sc;
+ CalculateSymbolContext (&sc);
+ // Null out everything below the CompUnit 'cause we don't actually know these.
+
+ size_t bit_size = ClangASTContext::GetTypeBitSize ((GetType()->GetClangASTContext().getASTContext()), &arg_qualtype);
+ Type arg_type (0, GetType()->GetSymbolFile(), arg_return_name, bit_size, sc.comp_unit, 0, Type::eTypeUIDSynthetic, Declaration(), arg_qualtype.getAsOpaquePtr());
+ return arg_type;
+ }
+
+ return Type();
+}
+
+const char *
+Function::GetArgumentNameAtIndex (size_t idx)
+{
+ clang::Type *clang_type = static_cast<clang::QualType *>(GetType()->GetOpaqueClangQualType())->getTypePtr();
+ assert (clang_type->isFunctionType());
+ if (!clang_type->isFunctionProtoType())
+ return NULL;
+ return NULL;
+}
+
+bool
+Function::IsVariadic ()
+{
+ const clang::Type *clang_type = static_cast<clang::QualType *>(GetType()->GetOpaqueClangQualType())->getTypePtr();
+ assert (clang_type->isFunctionType());
+ if (!clang_type->isFunctionProtoType())
+ return false;
+
+ const clang::FunctionProtoType *function_proto_type = dyn_cast<clang::FunctionProtoType>(clang_type);
+ if (function_proto_type != NULL)
+ {
+ return function_proto_type->isVariadic();
+ }
+
+ return false;
+}
+
+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 line_entry;
+ if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(), line_entry))
+ m_prologue_byte_size = line_entry.range.GetByteSize();
+ }
+ }
+ return m_prologue_byte_size;
+}
+
+
+
diff --git a/lldb/source/Symbol/LineEntry.cpp b/lldb/source/Symbol/LineEntry.cpp
new file mode 100644
index 00000000000..cdc3c54eaa3
--- /dev/null
+++ b/lldb/source/Symbol/LineEntry.cpp
@@ -0,0 +1,237 @@
+//===-- 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"
+
+using namespace lldb_private;
+
+LineEntry::LineEntry() :
+ range(),
+ file(),
+ line(0),
+ column(0),
+ is_start_of_statement(0),
+ is_start_of_basic_block(0),
+ is_terminal_entry(0),
+ is_prologue_end(0),
+ is_epilogue_begin(0)
+{
+}
+
+LineEntry::LineEntry
+(
+ lldb_private::Section *section,
+ 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, 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) const
+{
+ bool result = false;
+ if (file)
+ {
+ file.Dump (s);
+ if (line)
+ s->PutChar(':');
+ result = true;
+ }
+ if (line)
+ s->Printf ("%u", line);
+ else
+ result = false;
+
+ return result;
+}
+
+bool
+LineEntry::Dump
+(
+ Stream *s,
+ Process *process,
+ bool show_file,
+ Address::DumpStyle style,
+ Address::DumpStyle fallback_style,
+ bool show_range
+) const
+{
+ if (show_range)
+ {
+ // Show address range
+ if (!range.Dump(s, process, style, fallback_style))
+ return false;
+ }
+ else
+ {
+ // Show address only
+ if (!range.GetBaseAddress().Dump(s,
+ process,
+ style,
+ fallback_style))
+ return false;
+ }
+ if (line)
+ s->Printf(", line = %u", line);
+ if (column)
+ s->Printf(", column = %u", column);
+ if (show_file)
+ {
+ *s << ", file = " << file;
+ }
+ 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, Process *process) const
+{
+
+ if (level == lldb::eDescriptionLevelBrief || level == lldb::eDescriptionLevelFull)
+ {
+ // Show address only
+ range.GetBaseAddress().Dump(s, process, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
+
+ if (file)
+ *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, process, 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/lldb/source/Symbol/LineTable.cpp b/lldb/source/Symbol/LineTable.cpp
new file mode 100644
index 00000000000..326fd6e0e78
--- /dev/null
+++ b/lldb/source/Symbol/LineTable.cpp
@@ -0,0 +1,332 @@
+//===-- 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/Section.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// LineTable constructor
+//----------------------------------------------------------------------
+LineTable::LineTable(CompileUnit* comp_unit) :
+ m_comp_unit(comp_unit),
+ m_section_list(),
+ m_entries()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+LineTable::~LineTable()
+{
+}
+
+//void
+//LineTable::AddLineEntry(const LineEntry& entry)
+//{
+// // Do a binary search for the correct entry and insert it
+// m_line_entries.insert(std::upper_bound(m_line_entries.begin(), m_line_entries.end(), entry), entry);
+//}
+
+void
+LineTable::AppendLineEntry
+(
+ SectionSP& section_sp,
+ lldb::addr_t section_offset,
+ 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
+)
+{
+ uint32_t sect_idx = m_section_list.AddUniqueSection (section_sp);
+ // Make sure we don't user more than 256 sections as that is all we have
+ // room for in the LineTable::Entry::m_sect_idx. If this assert fires,
+ // we will need to m_sect_idx have more bits...
+ assert((section_offset & 0xffffffffff000000ull) == 0);
+ Entry entry(sect_idx, section_offset, line, column, file_idx, is_start_of_statement, is_start_of_basic_block, is_prologue_end, is_epilogue_begin, is_terminal_entry);
+ m_entries.push_back (entry);
+}
+
+
+void
+LineTable::InsertLineEntry
+(
+ SectionSP& section_sp,
+ lldb::addr_t section_offset,
+ 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
+)
+{
+ SectionSP line_section_sp(section_sp);
+ const Section *linked_section = line_section_sp->GetLinkedSection();
+ if (linked_section)
+ {
+ section_offset += line_section_sp->GetLinkedOffset();
+ line_section_sp = linked_section->GetSharedPointer();
+ assert(line_section_sp.get());
+ }
+
+ uint32_t sect_idx = m_section_list.AddUniqueSection (line_section_sp);
+ // Make sure we don't user more than 256 sections as that is all we have
+ // room for in the LineTable::Entry::m_sect_idx. If this assert fires,
+ // we will need to m_sect_idx have more bits...
+ assert((section_offset & 0xffffffffff000000ull) == 0);
+ Entry entry(sect_idx, section_offset, 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);
+}
+
+//----------------------------------------------------------------------
+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
+{
+ if (a.sect_idx == b.sect_idx)
+ {
+ #define LT_COMPARE(a,b) if (a != b) return a < b
+ LT_COMPARE (a.sect_offset, b.sect_offset);
+ 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);
+ // b and a reversed on purpose below.
+ LT_COMPARE (b.is_terminal_entry, a.is_terminal_entry);
+ LT_COMPARE (a.file_idx, b.file_idx);
+ return false;
+ #undef LT_COMPARE;
+ }
+
+ const Section *a_section = m_line_table->GetSectionForEntryIndex (a.sect_idx);
+ const Section *b_section = m_line_table->GetSectionForEntryIndex (b.sect_idx);
+ return Section::Compare(*a_section, *b_section) < 0;
+};
+
+
+Section *
+LineTable::GetSectionForEntryIndex (uint32_t idx)
+{
+ if (idx < m_section_list.GetSize())
+ return m_section_list.GetSectionAtIndex(idx).get();
+ return NULL;
+}
+
+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;
+ uint32_t sect_idx = m_section_list.FindSectionIndex (so_addr.GetSection());
+ if (sect_idx != UINT32_MAX)
+ {
+ Entry search_entry;
+ search_entry.sect_idx = sect_idx;
+ search_entry.sect_offset = so_addr.GetOffset();
+
+ 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->sect_offset != search_entry.sect_offset)
+ --pos;
+ else if (pos->sect_offset == search_entry.sect_offset)
+ {
+ while (pos != begin_pos)
+ {
+ entry_collection::const_iterator prev_pos = pos - 1;
+ if (prev_pos->sect_idx == search_entry.sect_idx &&
+ prev_pos->sect_offset == search_entry.sect_offset)
+ --pos;
+ else
+ break;
+ }
+ }
+
+ }
+ 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];
+ line_entry.range.GetBaseAddress().SetSection(m_section_list.GetSectionAtIndex (entry.sect_idx).get());
+ line_entry.range.GetBaseAddress().SetOffset(entry.sect_offset);
+ if (!entry.is_terminal_entry && idx + 1 < m_entries.size())
+ {
+ const Entry& next_entry = m_entries[idx+1];
+ if (next_entry.sect_idx == entry.sect_idx)
+ {
+ line_entry.range.SetByteSize(next_entry.sect_offset - entry.sect_offset);
+ }
+ else
+ {
+ Address next_line_addr(m_section_list.GetSectionAtIndex (next_entry.sect_idx).get(), next_entry.sect_offset);
+ line_entry.range.SetByteSize(next_line_addr.GetFileAddress() - line_entry.range.GetBaseAddress().GetFileAddress());
+ }
+ }
+ 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, uint32_t file_idx, uint32_t line, bool exact, LineEntry* line_entry_ptr)
+{
+ const size_t count = m_entries.size();
+ size_t best_match = UINT_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 != UINT_MAX)
+ {
+ if (line_entry_ptr)
+ ConvertEntryAtIndexToLineEntry (best_match, *line_entry_ptr);
+ return best_match;
+ }
+ return UINT_MAX;
+}
+
+void
+LineTable::Dump (Stream *s, Process *process, 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, process, prev_file != line_entry.file, style, fallback_style, show_line_ranges);
+ s->EOL();
+ prev_file = line_entry.file;
+ }
+}
+
+
+void
+LineTable::GetDescription (Stream *s, Process *process, 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, process);
+ s->EOL();
+ }
+}
+
+
+
diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp
new file mode 100644
index 00000000000..8d224488641
--- /dev/null
+++ b/lldb/source/Symbol/ObjectFile.cpp
@@ -0,0 +1,92 @@
+//===-- 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/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/ObjectContainer.h"
+#include "lldb/Symbol/SymbolFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ObjectFile*
+ObjectFile::FindPlugin (Module* module, const FileSpec* file, lldb::addr_t file_offset, lldb::addr_t file_size)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "ObjectFile::FindPlugin (module = %s/%s, file = %p, file_offset = 0x%z8.8x, file_size = 0x%z8.8x)",
+ module->GetFileSpec().GetDirectory().AsCString(),
+ module->GetFileSpec().GetFilename().AsCString(),
+ file, file_offset, file_size);
+ std::auto_ptr<ObjectFile> object_file_ap;
+
+ if (module != NULL)
+ {
+ if (file)
+ {
+ if (file_size == 0)
+ file_size = file->GetByteSize();
+
+ if (file_size == 0)
+ {
+ // Check for archive file with format "/path/to/archive.a(object.o)"
+ char path_with_object[PATH_MAX*2];
+ module->GetFileSpec().GetPath(path_with_object, sizeof(path_with_object));
+
+ RegularExpression g_object_regex("(.*)\\(([^\\)]+)\\)$");
+ if (g_object_regex.Execute (path_with_object, 2))
+ {
+ FileSpec archive_file;
+ std::string path;
+ std::string object;
+ if (g_object_regex.GetMatchAtIndex (path_with_object, 1, path) &&
+ g_object_regex.GetMatchAtIndex (path_with_object, 2, object))
+ {
+ archive_file.SetFile (path.c_str());
+ file_size = archive_file.GetByteSize();
+ if (file_size > 0)
+ module->SetFileSpecAndObjectName (archive_file, ConstString(object.c_str()));
+ }
+ }
+ }
+
+ DataBufferSP file_header_data_sp(file->ReadFileContents(file_offset, 512));
+ uint32_t idx;
+
+ // Check if this is a normal object file by iterating through
+ // all object file plugin instances.
+ ObjectFileCreateInstance create_object_file_callback;
+ for (idx = 0; (create_object_file_callback = PluginManager::GetObjectFileCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ object_file_ap.reset (create_object_file_callback(module, file_header_data_sp, file, file_offset, file_size));
+ if (object_file_ap.get())
+ return object_file_ap.release();
+ }
+
+ // 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.
+ ObjectContainerCreateInstance create_object_container_callback;
+ for (idx = 0; (create_object_container_callback = PluginManager::GetObjectContainerCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ std::auto_ptr<ObjectContainer> object_container_ap(create_object_container_callback(module, file_header_data_sp, file, file_offset, file_size));
+
+ if (object_container_ap.get())
+ object_file_ap.reset (object_container_ap->GetObjectFile(file));
+
+ if (object_file_ap.get())
+ return object_file_ap.release();
+ }
+ }
+ }
+ return NULL;
+}
diff --git a/lldb/source/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp
new file mode 100644
index 00000000000..fb01fc176bd
--- /dev/null
+++ b/lldb/source/Symbol/Symbol.cpp
@@ -0,0 +1,463 @@
+//===-- 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/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+Symbol::Symbol() :
+ UserID (),
+ m_mangled (),
+ m_type (eSymbolTypeInvalid),
+ 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_searched_for_function (false),
+ m_addr_range (),
+ m_flags (),
+ m_function (NULL)
+{
+}
+
+Symbol::Symbol
+(
+ user_id_t symID,
+ const char *name,
+ bool name_is_mangled,
+ SymbolType type,
+ bool external,
+ bool is_debug,
+ bool is_trampoline,
+ bool is_artificial,
+ const Section* section,
+ addr_t offset,
+ uint32_t size,
+ uint32_t flags
+) :
+ UserID (symID),
+ m_mangled (name, name_is_mangled),
+ m_type (type),
+ 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_searched_for_function (false),
+ m_addr_range (section, offset, size),
+ m_flags (flags),
+ m_function (NULL)
+{
+}
+
+Symbol::Symbol
+(
+ user_id_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,
+ uint32_t flags
+) :
+ UserID (symID),
+ m_mangled (name, name_is_mangled),
+ m_type (type),
+ 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_searched_for_function (false),
+ m_addr_range (range),
+ m_flags (flags),
+ m_function (NULL)
+{
+}
+
+Symbol::Symbol(const Symbol& rhs):
+ UserID (rhs),
+ m_mangled (rhs.m_mangled),
+ m_type (rhs.m_type),
+ 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_searched_for_function (false),
+ m_addr_range (rhs.m_addr_range),
+ m_flags (rhs.m_flags),
+ m_function (NULL)
+{
+}
+
+const Symbol&
+Symbol::operator= (const Symbol& rhs)
+{
+ if (this != &rhs)
+ {
+ UserID::operator= (rhs);
+ m_mangled = rhs.m_mangled;
+ m_type = rhs.m_type;
+ 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_searched_for_function = rhs.m_searched_for_function;
+ m_addr_range = rhs.m_addr_range;
+ m_flags = rhs.m_flags;
+ m_function = rhs.m_function;
+ }
+ return *this;
+}
+
+AddressRange &
+Symbol::GetAddressRangeRef()
+{
+ return m_addr_range;
+}
+
+const AddressRange &
+Symbol::GetAddressRangeRef() const
+{
+ return m_addr_range;
+}
+
+AddressRange *
+Symbol::GetAddressRangePtr()
+{
+ if (m_addr_range.GetBaseAddress().GetSection())
+ return &m_addr_range;
+ return NULL;
+}
+
+const AddressRange *
+Symbol::GetAddressRangePtr() const
+{
+ if (m_addr_range.GetBaseAddress().GetSection())
+ return &m_addr_range;
+ return NULL;
+}
+
+bool
+Symbol::GetSizeIsSibling() const
+{
+ return m_size_is_sibling;
+}
+
+bool
+Symbol::GetSizeIsSynthesized() const
+{
+ return m_size_is_synthesized;
+}
+
+uint32_t
+Symbol::GetSiblingIndex() const
+{
+ return m_size_is_sibling ? m_addr_range.GetByteSize() : 0;
+}
+
+uint32_t
+Symbol::GetFlags() const
+{
+ return m_flags;
+}
+
+void
+Symbol::SetFlags (uint32_t flags)
+{
+ m_flags = flags;
+}
+
+SymbolType
+Symbol::GetType() const
+{
+ return m_type;
+}
+
+void
+Symbol::SetType(SymbolType type)
+{
+ m_type = type;
+}
+
+bool
+Symbol::IsSynthetic () const
+{
+ return m_is_synthetic;
+}
+
+void
+Symbol::SetIsSynthetic (bool b)
+{
+ m_is_synthetic = b;
+}
+
+void
+Symbol::SetSizeIsSynthesized(bool b)
+{
+ m_size_is_synthesized = b;
+}
+
+
+bool
+Symbol::IsDebug() const
+{
+ return m_is_debug;
+}
+
+void
+Symbol::SetDebug (bool b)
+{
+ m_is_debug = b;
+}
+
+bool
+Symbol::IsExternal() const
+{
+ return m_is_external;
+}
+
+void
+Symbol::SetExternal(bool b)
+{
+ m_is_external = b;
+}
+
+bool
+Symbol::IsTrampoline () const
+{
+ return m_type == eSymbolTypeTrampoline;
+}
+
+uint32_t
+Symbol::GetByteSize() const
+{
+ return m_addr_range.GetByteSize();
+}
+
+void
+Symbol::SetByteSize (uint32_t size)
+{
+ m_addr_range.SetByteSize(size);
+}
+
+void
+Symbol::SetSizeIsSibling (bool b)
+{
+ m_size_is_sibling = b;
+}
+
+void
+Symbol::Dump(Stream *s, Process *process, 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());
+
+ const Section *section = m_addr_range.GetBaseAddress().GetSection();
+ if (section != NULL)
+ {
+ if (!m_addr_range.GetBaseAddress().Dump(s, NULL, Address::DumpStyleFileAddress))
+ s->Printf("%*s", 18, "");
+
+ s->PutChar(' ');
+
+ if (!m_addr_range.GetBaseAddress().Dump(s, process, Address::DumpStyleLoadAddress))
+ s->Printf("%*s", 18, "");
+
+ const char *format = m_size_is_sibling ?
+ " Sibling -> [%5llu] 0x%8.8x %s\n":
+ " 0x%16.16llx 0x%8.8x %s\n";
+ s->Printf( format,
+ m_addr_range.GetByteSize(),
+ m_flags,
+ m_mangled.GetName().AsCString(""));
+ }
+ else
+ {
+ const char *format = m_size_is_sibling ?
+ "0x%16.16llx Sibling -> [%5llu] 0x%8.8x %s\n":
+ "0x%16.16llx 0x%16.16llx 0x%8.8x %s\n";
+ s->Printf( format,
+ m_addr_range.GetBaseAddress().GetOffset(),
+ m_addr_range.GetByteSize(),
+ m_flags,
+ m_mangled.GetName().AsCString(""));
+ }
+}
+
+const Mangled&
+Symbol::GetMangled() const
+{
+ return m_mangled;
+}
+
+Mangled&
+Symbol::GetMangled()
+{
+ return m_mangled;
+}
+
+Address &
+Symbol::GetValue()
+{
+ return m_addr_range.GetBaseAddress();
+}
+
+const Address &
+Symbol::GetValue() const
+{
+ return m_addr_range.GetBaseAddress();
+}
+
+void
+Symbol::SetValue (Address &value)
+{
+ m_addr_range.GetBaseAddress() = value;
+}
+
+Function *
+Symbol::GetFunction ()
+{
+ if (m_function == NULL && !m_searched_for_function)
+ {
+ m_searched_for_function = true;
+ Module *module = m_addr_range.GetBaseAddress().GetModule();
+ if (module)
+ {
+ SymbolContext sc;
+ if (module->ResolveSymbolContextForAddress(m_addr_range.GetBaseAddress(), eSymbolContextFunction, sc))
+ m_function = sc.function;
+ }
+ }
+ return m_function;
+}
+
+uint32_t
+Symbol::GetPrologueByteSize ()
+{
+ if (m_type == eSymbolTypeCode || m_type == eSymbolTypeFunction)
+ {
+ if (!m_type_data_resolved)
+ {
+ m_type_data_resolved = true;
+ Module *module = m_addr_range.GetBaseAddress().GetModule();
+ SymbolContext sc;
+ if (module && module->ResolveSymbolContextForAddress (m_addr_range.GetBaseAddress(),
+ eSymbolContextLineEntry,
+ sc))
+ {
+ m_type_data = sc.line_entry.range.GetByteSize();
+ }
+ else
+ {
+ // TODO: expose something in Process to figure out the
+ // size of a function prologue.
+ }
+ }
+ return m_type_data;
+ }
+ return 0;
+}
+
+void
+Symbol::SetValue (const AddressRange &range)
+{
+ m_addr_range = range;
+}
+
+
+void
+Symbol::SetValue(addr_t value)
+{
+ m_addr_range.GetBaseAddress().SetSection(NULL);
+ m_addr_range.GetBaseAddress().SetOffset(value);
+}
+
+
+bool
+Symbol::Compare(const ConstString& name, SymbolType type) const
+{
+ if (m_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(Extern);
+ 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(Function);
+ ENUM_TO_CSTRING(FunctionEnd);
+ ENUM_TO_CSTRING(CommonBlock);
+ ENUM_TO_CSTRING(Block);
+ ENUM_TO_CSTRING(Static);
+ ENUM_TO_CSTRING(Global);
+ 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);
+ default:
+ break;
+ }
+ return "<unknown SymbolType>";
+}
+
diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp
new file mode 100644
index 00000000000..0a33d5adbf0
--- /dev/null
+++ b/lldb/source/Symbol/SymbolContext.cpp
@@ -0,0 +1,424 @@
+//===-- 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/Symbol/CompileUnit.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Symbol/SymbolVendor.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);
+}
+
+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()
+{
+ target_sp.reset();
+ module_sp.reset();
+ comp_unit = NULL;
+ function = NULL;
+ block = NULL;
+ line_entry.Clear();
+ symbol = NULL;
+}
+
+void
+SymbolContext::DumpStopContext
+(
+ Stream *s,
+ ExecutionContextScope *exe_scope,
+ const Address &addr,
+ bool show_module
+) const
+{
+ Process *process = NULL;
+ if (exe_scope)
+ process = exe_scope->CalculateProcess();
+ addr_t load_addr = addr.GetLoadAddress (process);
+
+ if (show_module && module_sp)
+ {
+ *s << module_sp->GetFileSpec().GetFilename() << '`';
+ }
+
+ if (function != NULL)
+ {
+ if (function->GetMangled().GetName())
+ function->GetMangled().GetName().Dump(s);
+
+ const addr_t func_load_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress(process);
+ if (load_addr > func_load_addr)
+ s->Printf(" + %llu", load_addr - func_load_addr);
+
+ if (block != NULL)
+ {
+ s->IndentMore();
+ block->DumpStopContext(s, this);
+ s->IndentLess();
+ }
+ else
+ {
+ if (line_entry.IsValid())
+ {
+ s->PutCString(" at ");
+ if (line_entry.DumpStopContext(s))
+ return;
+ }
+ }
+ }
+ else if (symbol != NULL)
+ {
+ symbol->GetMangled().GetName().Dump(s);
+
+ if (symbol->GetAddressRangePtr())
+ {
+ const addr_t sym_load_addr = symbol->GetAddressRangePtr()->GetBaseAddress().GetLoadAddress(process);
+ if (load_addr > sym_load_addr)
+ s->Printf(" + %llu", load_addr - sym_load_addr);
+ }
+ }
+ else
+ {
+ addr.Dump(s, exe_scope, Address::DumpStyleModuleWithFileAddress);
+ }
+}
+
+void
+SymbolContext::Dump(Stream *s, Process *process) 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 << " {" << comp_unit->GetID() << "} " << *(dynamic_cast<FileSpec*> (comp_unit));
+ s->EOL();
+ s->Indent();
+ *s << "Function = " << (void *)function;
+ if (function != NULL)
+ {
+ *s << " {" << function->GetID() << "} ";/// << function->GetType()->GetName();
+// Type* func_type = function->Type();
+// if (func_type)
+// {
+// s->EOL();
+// const UserDefType* func_udt = func_type->GetUserDefinedType().get();
+// if (func_udt)
+// {
+// s->IndentMore();
+// func_udt->Dump(s, func_type);
+// s->IndentLess();
+// }
+// }
+ }
+ s->EOL();
+ s->Indent();
+ *s << "Block = " << (void *)block;
+ if (block != NULL)
+ *s << " {" << 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, process, 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.target_sp.get() == rhs.target_sp.get() &&
+ lhs.module_sp.get() == rhs.module_sp.get() &&
+ lhs.comp_unit == rhs.comp_unit &&
+ lhs.function == rhs.function &&
+ LineEntry::Compare(lhs.line_entry, rhs.line_entry) == 0 &&
+ lhs.symbol == rhs.symbol;
+}
+
+bool
+lldb_private::operator!= (const SymbolContext& lhs, const SymbolContext& rhs)
+{
+ return lhs.target_sp.get() != rhs.target_sp.get() ||
+ lhs.module_sp.get() != rhs.module_sp.get() ||
+ lhs.comp_unit != rhs.comp_unit ||
+ lhs.function != rhs.function ||
+ LineEntry::Compare(lhs.line_entry, rhs.line_entry) != 0 ||
+ lhs.symbol != rhs.symbol;
+}
+
+bool
+SymbolContext::GetAddressRange (uint32_t scope, AddressRange &range) const
+{
+ if ((scope & eSymbolContextLineEntry) && line_entry.IsValid())
+ {
+ range = line_entry.range;
+ return true;
+ }
+ else if ((scope & eSymbolContextFunction) && function != NULL)
+ {
+ range = function->GetAddressRange();
+ return true;
+ }
+ else if ((scope & eSymbolContextSymbol) && symbol != NULL && symbol->GetAddressRangePtr())
+ {
+ range = *symbol->GetAddressRangePtr();
+
+ if (range.GetByteSize() == 0)
+ {
+ if (module_sp)
+ {
+ ObjectFile *objfile = module_sp->GetObjectFile();
+ if (objfile)
+ {
+ Symtab *symtab = objfile->GetSymtab();
+ if (symtab)
+ range.SetByteSize(symtab->CalculateSymbolSize (symbol));
+ }
+ }
+ }
+ return true;
+ }
+ range.Clear();
+ return false;
+}
+
+
+Function *
+SymbolContext::FindFunctionByName (const char *name) const
+{
+ ConstString name_const_str (name);
+ if (function != NULL)
+ {
+ // FIXME: Look in the class of the current function, if it exists,
+ // for methods matching name.
+ }
+
+ //
+ if (comp_unit != NULL)
+ {
+ // Make sure we've read in all the functions. We should be able to check and see
+ // if there's one by this name present before we do this...
+ module_sp->GetSymbolVendor()->ParseCompileUnitFunctions(*this);
+ uint32_t func_idx;
+ lldb::FunctionSP func_sp;
+ for (func_idx = 0; (func_sp = comp_unit->GetFunctionAtIndex(func_idx)) != NULL; ++func_idx)
+ {
+ if (func_sp->GetMangled().GetName() == name_const_str)
+ return func_sp.get();
+ }
+ }
+ if (module_sp != NULL)
+ {
+ SymbolContextList sc_matches;
+ if (module_sp->FindFunctions (name_const_str, false, sc_matches) > 0)
+ {
+ SymbolContext sc;
+ sc_matches.GetContextAtIndex (0, sc);
+ return sc.function;
+ }
+ }
+
+ if (target_sp)
+ {
+ SymbolContextList sc_matches;
+ if (target_sp->GetImages().FindFunctions (name_const_str, sc_matches) > 0)
+ {
+ SymbolContext sc;
+ sc_matches.GetContextAtIndex (0, sc);
+ return sc.function;
+ }
+ }
+
+ return NULL;
+}
+
+lldb::VariableSP
+SymbolContext::FindVariableByName (const char *name) const
+{
+ lldb::VariableSP return_value;
+ return return_value;
+}
+
+lldb::TypeSP
+SymbolContext::FindTypeByName (const char *name) const
+{
+ lldb::TypeSP return_value;
+ return return_value;
+}
+
+//----------------------------------------------------------------------
+//
+// SymbolContextList
+//
+//----------------------------------------------------------------------
+
+
+SymbolContextList::SymbolContextList() :
+ m_symbol_contexts()
+{
+}
+
+SymbolContextList::~SymbolContextList()
+{
+}
+
+void
+SymbolContextList::Append(const SymbolContext& sc)
+{
+ m_symbol_contexts.push_back(sc);
+}
+
+void
+SymbolContextList::Clear()
+{
+ m_symbol_contexts.clear();
+}
+
+void
+SymbolContextList::Dump(Stream *s, Process *process) 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, process);
+ }
+ s->IndentLess();
+}
+
+bool
+SymbolContextList::GetContextAtIndex(uint32_t idx, SymbolContext& sc) const
+{
+ if (idx < m_symbol_contexts.size())
+ {
+ sc = m_symbol_contexts[idx];
+ return true;
+ }
+ return false;
+}
+
+bool
+SymbolContextList::RemoveContextAtIndex (uint32_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();
+}
diff --git a/lldb/source/Symbol/SymbolFile.cpp b/lldb/source/Symbol/SymbolFile.cpp
new file mode 100644
index 00000000000..edfd56d3bd9
--- /dev/null
+++ b/lldb/source/Symbol/SymbolFile.cpp
@@ -0,0 +1,50 @@
+//===-- 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/lldb-private.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Core/PluginManager.h"
+
+using namespace lldb_private;
+
+SymbolFile*
+SymbolFile::FindPlugin (ObjectFile* obj_file)
+{
+ std::auto_ptr<SymbolFile> best_sym_file_ap;
+ if (obj_file != NULL)
+ {
+ // 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.
+
+ //----------------------------------------------------------------------
+ // We currently only have one debug symbol parser...
+ //----------------------------------------------------------------------
+ std::auto_ptr<SymbolFile> best_symfile_ap;
+ uint32_t best_symfile_abilities = 0;
+
+ SymbolFileCreateInstance create_callback;
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetSymbolFileCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ std::auto_ptr<SymbolFile> curr_symfile_ap(create_callback(obj_file));
+
+ if (curr_symfile_ap.get())
+ {
+ uint32_t sym_file_abilities = curr_symfile_ap->GetAbilities();
+ if (sym_file_abilities > best_symfile_abilities)
+ {
+ best_symfile_abilities = sym_file_abilities;
+ best_sym_file_ap = curr_symfile_ap;
+ }
+ }
+ }
+ }
+ return best_sym_file_ap.release();
+}
+
+
diff --git a/lldb/source/Symbol/SymbolVendor.mm b/lldb/source/Symbol/SymbolVendor.mm
new file mode 100644
index 00000000000..5fb8b0ab8d1
--- /dev/null
+++ b/lldb/source/Symbol/SymbolVendor.mm
@@ -0,0 +1,386 @@
+//===-- 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/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 (Module* module)
+{
+ std::auto_ptr<SymbolVendor> instance_ap;
+ //----------------------------------------------------------------------
+ // We currently only have one debug symbol parser...
+ //----------------------------------------------------------------------
+ SymbolVendorCreateInstance create_callback;
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetSymbolVendorCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ instance_ap.reset(create_callback(module));
+
+ if (instance_ap.get())
+ {
+ // TODO: make sure this symbol vendor is what we want. We
+ // currently are just returning the first one we find, but
+ // we may want to call this function only when we have our
+ // main executable module and then give all symbol vendor
+ // plug-ins a chance to compete for who wins.
+ 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));
+ if (instance_ap.get())
+ instance_ap->AddSymbolFileRepresendation(module->GetObjectFile());
+ return instance_ap.release();
+}
+
+//----------------------------------------------------------------------
+// SymbolVendor constructor
+//----------------------------------------------------------------------
+SymbolVendor::SymbolVendor(Module *module) :
+ ModuleChild(module),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_type_list(),
+ m_compile_units(),
+ m_sym_file_ap()
+{
+ ObjectFile * objfile = module->GetObjectFile();
+ ConstString target_triple;
+ if (objfile && objfile->GetTargetTriple(target_triple))
+ {
+ m_type_list.GetClangASTContext().SetTargetTriple (target_triple.AsCString());
+ }
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SymbolVendor::~SymbolVendor()
+{
+}
+
+//----------------------------------------------------------------------
+// Add a represantion given an object file.
+//----------------------------------------------------------------------
+void
+SymbolVendor::AddSymbolFileRepresendation(ObjectFile *obj_file)
+{
+ Mutex::Locker locker(m_mutex);
+ if (obj_file != NULL)
+ m_sym_file_ap.reset(SymbolFile::FindPlugin(obj_file));
+}
+
+bool
+SymbolVendor::SetCompileUnitAtIndex
+(CompUnitSP& cu, uint32_t idx)
+{
+ Mutex::Locker locker(m_mutex);
+ const uint32_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;
+ return true;
+ }
+ return false;
+}
+
+uint32_t
+SymbolVendor::GetNumCompileUnits()
+{
+ Mutex::Locker locker(m_mutex);
+ 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();
+}
+
+size_t
+SymbolVendor::ParseCompileUnitFunctions (const SymbolContext &sc)
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseCompileUnitFunctions(sc);
+ return 0;
+}
+
+bool
+SymbolVendor::ParseCompileUnitLineTable (const SymbolContext &sc)
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseCompileUnitLineTable(sc);
+ return false;
+}
+
+bool
+SymbolVendor::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files)
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseCompileUnitSupportFiles(sc, support_files);
+ return false;
+}
+
+size_t
+SymbolVendor::ParseFunctionBlocks (const SymbolContext &sc)
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseFunctionBlocks(sc);
+ return 0;
+}
+
+size_t
+SymbolVendor::ParseTypes (const SymbolContext &sc)
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseTypes(sc);
+ return 0;
+}
+
+size_t
+SymbolVendor::ParseVariablesForContext (const SymbolContext& sc)
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseVariablesForContext(sc);
+ return 0;
+}
+
+Type*
+SymbolVendor::ResolveTypeUID(lldb::user_id_t type_uid)
+{
+ Mutex::Locker locker(m_mutex);
+ 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)
+{
+ Mutex::Locker locker(m_mutex);
+ 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)
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ResolveSymbolContext(file_spec, line, check_inlines, resolve_scope, sc_list);
+ return 0;
+}
+
+uint32_t
+SymbolVendor::FindGlobalVariables (const ConstString &name, bool append, uint32_t max_matches, VariableList& variables)
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->FindGlobalVariables(name, append, max_matches, variables);
+ return 0;
+}
+
+uint32_t
+SymbolVendor::FindGlobalVariables (const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->FindGlobalVariables(regex, append, max_matches, variables);
+ return 0;
+}
+
+uint32_t
+SymbolVendor::FindFunctions(const ConstString &name, bool append, SymbolContextList& sc_list)
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->FindFunctions(name, append, sc_list);
+ return 0;
+}
+
+uint32_t
+SymbolVendor::FindFunctions(const RegularExpression& regex, bool append, SymbolContextList& sc_list)
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->FindFunctions(regex, append, sc_list);
+ return 0;
+}
+
+
+
+//uint32_t
+//SymbolVendor::FindTypes(const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, const char *udt_name, TypeList& types)
+//{
+// Mutex::Locker locker(m_mutex);
+// if (m_sym_file_ap.get())
+// {
+// lldb::user_id_t udt_uid = LLDB_INVALID_UID;
+// if (encoding == Type::user_defined_type)
+// udt_uid = UserDefType::GetUserDefTypeUID(udt_name);
+//
+// return m_sym_file_ap->FindTypes(sc, name, append, max_matches, encoding, udt_uid, types);
+// }
+// return 0;
+//}
+//
+//uint32_t
+//SymbolVendor::FindTypes(const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, const char *udt_name, TypeList& types)
+//{
+// Mutex::Locker locker(m_mutex);
+// if (m_sym_file_ap.get())
+// {
+// lldb::user_id_t udt_uid = LLDB_INVALID_UID;
+//
+// if (encoding == Type::user_defined_type)
+// udt_uid = UserDefType::GetUserDefTypeUID(udt_name);
+//
+// return m_sym_file_ap->FindTypes(sc, regex, append, max_matches, encoding, udt_uid, types);
+// }
+// return 0;
+//}
+
+void
+SymbolVendor::Dump(Stream *s)
+{
+ Mutex::Locker locker(m_mutex);
+ bool show_context = false;
+
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, 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(uint32_t idx)
+{
+ Mutex::Locker locker(m_mutex);
+ CompUnitSP cu_sp;
+ const uint32_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;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+SymbolVendor::GetPluginName()
+{
+ return "SymbolVendor";
+}
+
+const char *
+SymbolVendor::GetShortPluginName()
+{
+ return "vendor-default";
+}
+
+uint32_t
+SymbolVendor::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+SymbolVendor::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+SymbolVendor::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+SymbolVendor::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+
diff --git a/lldb/source/Symbol/Symtab.cpp b/lldb/source/Symbol/Symtab.cpp
new file mode 100644
index 00000000000..f1ed356d44b
--- /dev/null
+++ b/lldb/source/Symbol/Symtab.cpp
@@ -0,0 +1,596 @@
+//===-- 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/Timer.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symtab.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+Symtab::Symtab(ObjectFile *objfile) :
+ m_objfile(objfile),
+ m_symbols(),
+ m_addr_indexes(),
+ m_name_to_index()
+{
+}
+
+Symtab::~Symtab()
+{
+}
+
+void
+Symtab::Reserve(uint32_t count)
+{
+ m_symbols.reserve (count);
+}
+
+Symbol *
+Symtab::Resize(uint32_t count)
+{
+ m_symbols.resize (count);
+ return &m_symbols[0];
+}
+
+uint32_t
+Symtab::AddSymbol(const Symbol& symbol)
+{
+ uint32_t symbol_idx = m_symbols.size();
+ m_name_to_index.Clear();
+ m_addr_indexes.clear();
+ m_symbols.push_back(symbol);
+ return symbol_idx;
+}
+
+size_t
+Symtab::GetNumSymbols() const
+{
+ return m_symbols.size();
+}
+
+void
+Symtab::Dump(Stream *s, Process *process) const
+{
+ const_iterator pos;
+ 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%s, num_symbols = %u:\n",
+ file_spec.GetDirectory().AsCString(),
+ file_spec.GetFilename().AsCString(),
+ object_name ? "(" : "",
+ object_name ? object_name : "",
+ object_name ? ")" : "",
+ m_symbols.size());
+ else
+ s->Printf("Symtab, num_symbols = %u:\n", m_symbols.size());
+ s->IndentMore();
+
+ if (!m_symbols.empty())
+ {
+ const_iterator begin = m_symbols.begin();
+ const_iterator end = m_symbols.end();
+ DumpSymbolHeader (s);
+ for (pos = m_symbols.begin(); pos != end; ++pos)
+ {
+ s->Indent();
+ pos->Dump(s, process, std::distance(begin, pos));
+ }
+ }
+ s->IndentLess ();
+}
+
+void
+Symtab::Dump(Stream *s, Process *process, std::vector<uint32_t>& indexes) const
+{
+ const size_t num_symbols = GetNumSymbols();
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ s->Printf("Symtab %u symbol indexes (%u 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)
+ {
+ uint32_t idx = *pos;
+ if (idx < num_symbols)
+ {
+ s->Indent();
+ m_symbols[idx].Dump(s, process, 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");
+}
+
+Symbol *
+Symtab::SymbolAtIndex(uint32_t idx)
+{
+ if (idx < m_symbols.size())
+ return &m_symbols[idx];
+ return NULL;
+}
+
+
+const Symbol *
+Symtab::SymbolAtIndex(uint32_t idx) const
+{
+ if (idx < m_symbols.size())
+ return &m_symbols[idx];
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// InitNameIndexes
+//----------------------------------------------------------------------
+void
+Symtab::InitNameIndexes()
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
+ // Create the name index vector to be able to quickly search by name
+ const size_t count = m_symbols.size();
+ assert(m_objfile != NULL);
+ assert(m_objfile->GetModule() != NULL);
+ m_name_to_index.Reserve (count);
+
+ UniqueCStringMap<uint32_t>::Entry entry;
+
+ for (entry.value = 0; entry.value < count; ++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);
+
+ entry.cstring = mangled.GetDemangledName().GetCString();
+ if (entry.cstring && entry.cstring[0])
+ m_name_to_index.Append (entry);
+ }
+ m_name_to_index.Sort();
+}
+
+uint32_t
+Symtab::AppendSymbolIndexesWithType(SymbolType symbol_type, std::vector<uint32_t>& indexes, uint32_t start_idx, uint32_t end_index) const
+{
+ 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;
+}
+
+struct SymbolSortInfo
+{
+ const bool sort_by_load_addr;
+ const Symbol *symbols;
+};
+
+int
+Symtab::CompareSymbolValueByIndex (void *thunk, const void *a, const void *b)
+{
+ const Symbol *symbols = (const Symbol *)thunk;
+ uint32_t index_a = *((uint32_t *) a);
+ uint32_t index_b = *((uint32_t *) b);
+
+ addr_t value_a;
+ addr_t value_b;
+ if (symbols[index_a].GetValue().GetSection() == symbols[index_b].GetValue().GetSection())
+ {
+ value_a = symbols[index_a].GetValue ().GetOffset();
+ value_b = symbols[index_b].GetValue ().GetOffset();
+ }
+ else
+ {
+ value_a = symbols[index_a].GetValue ().GetFileAddress();
+ value_b = symbols[index_b].GetValue ().GetFileAddress();
+ }
+
+ 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 -1;
+ if (uid_a > uid_b)
+ return 1;
+ return 0;
+ }
+ else if (value_a < value_b)
+ return -1;
+
+ return 1;
+}
+
+void
+Symtab::SortSymbolIndexesByValue (std::vector<uint32_t>& indexes, bool remove_duplicates) const
+{
+ // No need to sort if we have zero or one items...
+ if (indexes.size() <= 1)
+ return;
+
+ // Sort the indexes in place using qsort
+ ::qsort_r (&indexes[0], indexes.size(), sizeof(uint32_t), (void *)&m_symbols[0], Symtab::CompareSymbolValueByIndex);
+
+ // 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)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
+ if (symbol_name)
+ {
+ const size_t old_size = indexes.size();
+ if (m_name_to_index.IsEmpty())
+ InitNameIndexes();
+
+ const char *symbol_cstr = symbol_name.GetCString();
+ const UniqueCStringMap<uint32_t>::Entry *entry_ptr;
+ for (entry_ptr = m_name_to_index.FindFirstValueForName (symbol_cstr);
+ entry_ptr!= NULL;
+ entry_ptr = m_name_to_index.FindNextValueForName (symbol_cstr, entry_ptr))
+ {
+ indexes.push_back (entry_ptr->value);
+ }
+ return indexes.size() - old_size;
+ }
+ return 0;
+}
+
+uint32_t
+Symtab::AppendSymbolIndexesWithNameAndType(const ConstString& symbol_name, SymbolType symbol_type, std::vector<uint32_t>& indexes)
+{
+ 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::AppendSymbolIndexesMatchingRegExAndType (const RegularExpression &regexp, SymbolType symbol_type, std::vector<uint32_t>& indexes)
+{
+ uint32_t prev_size = indexes.size();
+ uint32_t sym_end = m_symbols.size();
+
+ for (int 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;
+
+}
+
+Symbol *
+Symtab::FindSymbolWithType(SymbolType symbol_type, uint32_t& start_idx)
+{
+ const size_t count = m_symbols.size();
+ for (uint32_t idx = start_idx; idx < count; ++idx)
+ {
+ if (symbol_type == eSymbolTypeAny || m_symbols[idx].GetType() == symbol_type)
+ {
+ start_idx = idx;
+ return &m_symbols[idx];
+ }
+ }
+ return NULL;
+}
+
+const Symbol *
+Symtab::FindSymbolWithType(SymbolType symbol_type, uint32_t& start_idx) const
+{
+ const size_t count = m_symbols.size();
+ for (uint32_t idx = start_idx; idx < count; ++idx)
+ {
+ if (symbol_type == eSymbolTypeAny || m_symbols[idx].GetType() == symbol_type)
+ {
+ 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)
+{
+ 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_to_index.IsEmpty())
+ 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::FindAllSymbolsMatchingRexExAndType (const RegularExpression &regex, SymbolType symbol_type, std::vector<uint32_t>& symbol_indexes)
+{
+ AppendSymbolIndexesMatchingRegExAndType(regex, symbol_type, symbol_indexes);
+ return symbol_indexes.size();
+}
+
+Symbol *
+Symtab::FindFirstSymbolWithNameAndType (const ConstString &name, SymbolType symbol_type)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
+ if (m_name_to_index.IsEmpty())
+ 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, 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!
+ const AddressRange *curr_range = curr_symbol->GetAddressRangePtr();
+ if (curr_range)
+ {
+ const addr_t curr_file_addr = curr_range->GetBaseAddress().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;
+ const AddressRange *curr_range = symbol->GetAddressRangePtr();
+ if (curr_range)
+ {
+ const addr_t curr_file_addr = curr_range->GetBaseAddress().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), (comparison_function)SymbolWithClosestFileAddress);
+ return info;
+}
+
+
+void
+Symtab::InitAddressIndexes()
+{
+ if (m_addr_indexes.empty())
+ {
+ AppendSymbolIndexesWithType (eSymbolTypeFunction, m_addr_indexes);
+ AppendSymbolIndexesWithType (eSymbolTypeGlobal, m_addr_indexes);
+ AppendSymbolIndexesWithType (eSymbolTypeStatic, m_addr_indexes);
+ AppendSymbolIndexesWithType (eSymbolTypeCode, m_addr_indexes);
+ AppendSymbolIndexesWithType (eSymbolTypeTrampoline, m_addr_indexes);
+ AppendSymbolIndexesWithType (eSymbolTypeData, m_addr_indexes);
+ SortSymbolIndexesByValue(m_addr_indexes, true);
+ m_addr_indexes.push_back(UINT32_MAX); // Terminator for bsearch since we might need to look at the next symbol
+ }
+}
+
+size_t
+Symtab::CalculateSymbolSize (Symbol *symbol)
+{
+ // Make sure this symbol is from this symbol table...
+ if (symbol < m_symbols.data() && symbol >= m_symbols.data() + m_symbols.size())
+ return 0;
+
+ // See if this symbol already has a byte size?
+ size_t byte_size = symbol->GetByteSize();
+
+ if (byte_size)
+ {
+ // It does, just return it
+ return byte_size;
+ }
+
+ // Else if this is an address based symbol, figure out the delta between
+ // it and the next address based symbol
+ if (symbol->GetAddressRangePtr())
+ {
+ if (m_addr_indexes.empty())
+ InitAddressIndexes();
+ const size_t num_addr_indexes = m_addr_indexes.size();
+ SymbolSearchInfo info = FindIndexPtrForSymbolContainingAddress(this, symbol->GetAddressRangePtr()->GetBaseAddress().GetFileAddress(), m_addr_indexes.data(), num_addr_indexes);
+ if (info.match_index_ptr != NULL)
+ {
+ const lldb::addr_t curr_file_addr = symbol->GetAddressRangePtr()->GetBaseAddress().GetFileAddress();
+ // We can figure out the address range of all symbols except the
+ // last one by taking the delta between the current symbol and
+ // the next symbol
+
+ for (uint32_t addr_index = info.match_index_ptr - m_addr_indexes.data() + 1;
+ addr_index < num_addr_indexes;
+ ++addr_index)
+ {
+ Symbol *next_symbol = SymbolAtIndex(m_addr_indexes[addr_index]);
+ if (next_symbol == NULL)
+ break;
+
+ assert (next_symbol->GetAddressRangePtr());
+ const lldb::addr_t next_file_addr = next_symbol->GetAddressRangePtr()->GetBaseAddress().GetFileAddress();
+ if (next_file_addr > curr_file_addr)
+ {
+ byte_size = next_file_addr - curr_file_addr;
+ symbol->GetAddressRangePtr()->SetByteSize(byte_size);
+ symbol->SetSizeIsSynthesized(true);
+ break;
+ }
+ }
+ }
+ }
+ return byte_size;
+}
+
+Symbol *
+Symtab::FindSymbolWithFileAddress (addr_t file_addr)
+{
+ if (m_addr_indexes.empty())
+ InitAddressIndexes();
+
+ SymbolSearchInfo info = { this, file_addr, NULL, NULL, 0 };
+
+ uint32_t* match = (uint32_t*)bsearch(&info, &m_addr_indexes[0], m_addr_indexes.size(), sizeof(uint32_t), (comparison_function)SymbolWithFileAddress);
+ if (match)
+ return SymbolAtIndex (*match);
+ return NULL;
+}
+
+
+Symbol *
+Symtab::FindSymbolContainingFileAddress (addr_t file_addr, const uint32_t* indexes, uint32_t num_indexes)
+{
+ SymbolSearchInfo info = { this, file_addr, NULL, NULL, 0 };
+
+ bsearch(&info, indexes, num_indexes, sizeof(uint32_t), (comparison_function)SymbolWithClosestFileAddress);
+
+ if (info.match_symbol)
+ {
+ if (info.match_offset < CalculateSymbolSize(info.match_symbol))
+ return info.match_symbol;
+ }
+ return NULL;
+}
+
+Symbol *
+Symtab::FindSymbolContainingFileAddress (addr_t file_addr)
+{
+ if (m_addr_indexes.empty())
+ InitAddressIndexes();
+
+ return FindSymbolContainingFileAddress (file_addr, &m_addr_indexes[0], m_addr_indexes.size());
+}
+
diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp
new file mode 100644
index 00000000000..9338ea2839a
--- /dev/null
+++ b/lldb/source/Symbol/Type.cpp
@@ -0,0 +1,1531 @@
+//===-- 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 "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/AST/RecordLayout.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/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/ClangASTContext.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContextScope.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/TypeList.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+
+lldb_private::Type::Type
+(
+ lldb::user_id_t uid,
+ SymbolFile* symbol_file,
+ const ConstString &name,
+ uint64_t byte_size,
+ SymbolContextScope *context,
+ lldb::user_id_t encoding_uid,
+ EncodingUIDType encoding_uid_type,
+ const Declaration& decl,
+ void *clang_type
+) :
+ UserID (uid),
+ m_name (name),
+ m_byte_size (byte_size),
+ m_symbol_file (symbol_file),
+ m_context (context),
+ m_encoding_uid (encoding_uid),
+ m_encoding_uid_type (encoding_uid_type),
+ m_decl (decl),
+ m_clang_qual_type (clang_type)
+{
+}
+
+lldb_private::Type::Type () :
+ UserID (0),
+ m_name ("<INVALID TYPE>"),
+ m_byte_size (0),
+ m_symbol_file (NULL),
+ m_context (),
+ m_encoding_uid (0),
+ m_encoding_uid_type (eTypeInvalid),
+ m_decl (),
+ m_clang_qual_type (NULL)
+{
+}
+
+
+const lldb_private::Type&
+lldb_private::Type::operator= (const Type& rhs)
+{
+ if (this != &rhs)
+ {
+ UserID::operator= (rhs);
+ m_name = rhs.m_name;
+ m_byte_size = rhs.m_byte_size;
+ m_symbol_file = rhs.m_symbol_file;
+ m_context = rhs.m_context;
+ m_encoding_uid = rhs.m_encoding_uid;
+ m_decl = rhs.m_decl;
+ m_clang_qual_type = rhs.m_clang_qual_type;
+ }
+ return *this;
+}
+
+
+void
+lldb_private::Type::Dump (Stream *s, bool show_context)
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ *s << "Type" << (const UserID&)*this << ' ';
+ if (m_name)
+ *s << ", name = \"" << m_name << "\"";
+
+ if (m_byte_size != 0)
+ s->Printf(", size = %zu", m_byte_size);
+
+ if (show_context && m_context != NULL)
+ {
+ s->PutCString(", context = ( ");
+ m_context->DumpSymbolContext(s);
+ s->PutCString(" )");
+ }
+
+ m_decl.Dump(s);
+
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(m_clang_qual_type));
+
+ if (qual_type.getTypePtr())
+ {
+ *s << ", clang_type = ";
+
+ clang::TagType *tag_type = dyn_cast<clang::TagType>(qual_type.getTypePtr());
+ clang::TagDecl *tag_decl = NULL;
+ if (tag_type)
+ tag_decl = tag_type->getDecl();
+
+ if (tag_decl)
+ {
+ s->EOL();
+ s->EOL();
+ tag_decl->print(llvm::fouts(), 0);
+ s->EOL();
+ }
+ else
+ {
+ const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>();
+ if (typedef_type)
+ {
+ const clang::TypedefDecl *typedef_decl = typedef_type->getDecl();
+ std::string clang_typedef_name (typedef_decl->getQualifiedNameAsString());
+ if (!clang_typedef_name.empty())
+ *s << " (" << clang_typedef_name.c_str() << ')';
+ }
+ else
+ {
+ // We have a clang type, lets show it
+ TypeList *type_list = GetTypeList();
+ if (type_list)
+ {
+ clang::ASTContext *ast_context = GetClangAST();
+ if (ast_context)
+ {
+ std::string clang_type_name(qual_type.getAsString());
+ if (!clang_type_name.empty())
+ *s << " (" << clang_type_name.c_str() << ')';
+ }
+ }
+ }
+ }
+ }
+ else if (m_encoding_uid != LLDB_INVALID_UID)
+ {
+ *s << ", type_uid = " << m_encoding_uid;
+ switch (m_encoding_uid_type)
+ {
+ case eIsTypeWithUID: s->PutCString(" (unresolved type)"); break;
+ case eIsConstTypeWithUID: s->PutCString(" (unresolved const type)"); break;
+ case eIsRestrictTypeWithUID: s->PutCString(" (unresolved restrict type)"); break;
+ case eIsVolatileTypeWithUID: s->PutCString(" (unresolved volatile type)"); break;
+ case eTypedefToTypeWithUID: s->PutCString(" (unresolved typedef)"); break;
+ case ePointerToTypeWithUID: s->PutCString(" (unresolved pointer)"); break;
+ case eLValueReferenceToTypeWithUID: s->PutCString(" (unresolved L value reference)"); break;
+ case eRValueReferenceToTypeWithUID: s->PutCString(" (unresolved R value reference)"); break;
+ }
+ }
+
+//
+// if (m_access)
+// s->Printf(", access = %u", m_access);
+ s->EOL();
+}
+
+const lldb_private::ConstString &
+lldb_private::Type::GetName()
+{
+ if (!(m_name))
+ {
+ if (ResolveClangType())
+ {
+ std::string type_name = ClangASTContext::GetTypeName (m_clang_qual_type);
+ if (!type_name.empty())
+ m_name.SetCString (type_name.c_str());
+ }
+ }
+ return m_name;
+}
+
+int
+lldb_private::Type::DumpClangTypeName(Stream *s, void *clang_type)
+{
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
+ std::string type_name;
+ const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>();
+ if (typedef_type)
+ {
+ const clang::TypedefDecl *typedef_decl = typedef_type->getDecl();
+ type_name = typedef_decl->getQualifiedNameAsString();
+ }
+ else
+ {
+ type_name = qual_type.getAsString();
+ }
+ if (!type_name.empty())
+ return s->Printf("(%s) ", type_name.c_str());
+ return 0;
+}
+
+lldb_private::ConstString
+lldb_private::Type::GetClangTypeName (void *clang_type)
+{
+ ConstString clang_type_name;
+ if (clang_type)
+ {
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
+
+ const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>();
+ if (typedef_type)
+ {
+ const clang::TypedefDecl *typedef_decl = typedef_type->getDecl();
+ std::string clang_typedef_name (typedef_decl->getQualifiedNameAsString());
+ if (!clang_typedef_name.empty())
+ clang_type_name.SetCString (clang_typedef_name.c_str());
+ }
+ else
+ {
+ std::string type_name(qual_type.getAsString());
+ if (!type_name.empty())
+ clang_type_name.SetCString (type_name.c_str());
+ }
+ }
+ else
+ {
+ clang_type_name.SetCString ("<invalid>");
+ }
+
+ return clang_type_name;
+}
+
+
+
+void
+lldb_private::Type::DumpTypeName(Stream *s)
+{
+ GetName().Dump(s, "<invalid-type-name>");
+}
+
+
+void
+lldb_private::Type::DumpValue
+(
+ lldb_private::ExecutionContext *exe_ctx,
+ lldb_private::Stream *s,
+ const lldb_private::DataExtractor &data,
+ uint32_t data_byte_offset,
+ bool show_types,
+ bool show_summary,
+ bool verbose,
+ lldb::Format format
+)
+{
+ if (ResolveClangType())
+ {
+ if (show_types)
+ {
+ s->PutChar('(');
+ if (verbose)
+ s->Printf("Type{0x%8.8x} ", GetID());
+ DumpTypeName (s);
+ s->PutCString(") ");
+ }
+
+ lldb_private::Type::DumpValue (exe_ctx,
+ GetClangAST (),
+ m_clang_qual_type,
+ 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);
+ }
+}
+
+
+void
+lldb_private::Type::DumpSummary
+(
+ ExecutionContext *exe_ctx,
+ clang::ASTContext *ast_context,
+ void *clang_type,
+ Stream *s,
+ const lldb_private::DataExtractor &data,
+ uint32_t data_byte_offset,
+ size_t data_byte_size
+)
+{
+ uint32_t length = 0;
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
+ if (ClangASTContext::IsCStringType (clang_type, length))
+ {
+
+ if (exe_ctx && exe_ctx->process)
+ {
+ uint32_t offset = data_byte_offset;
+ lldb::addr_t pointer_addresss = data.GetMaxU64(&offset, data_byte_size);
+ const size_t k_max_buf_size = length ? length : 256;
+ uint8_t buf[k_max_buf_size + 1];
+ lldb_private::DataExtractor data(buf, k_max_buf_size, exe_ctx->process->GetByteOrder(), 4);
+ buf[k_max_buf_size] = '\0';
+ size_t bytes_read;
+ size_t total_cstr_len = 0;
+ Error error;
+ while ((bytes_read = exe_ctx->process->ReadMemory (pointer_addresss, buf, k_max_buf_size, error)) > 0)
+ {
+ const size_t len = strlen((const char *)buf);
+ if (len == 0)
+ break;
+ if (total_cstr_len == 0)
+ s->PutCString (" \"");
+ data.Dump(s, 0, lldb::eFormatChar, 1, len, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
+ total_cstr_len += len;
+ if (len < k_max_buf_size)
+ break;
+ pointer_addresss += total_cstr_len;
+ }
+ if (total_cstr_len > 0)
+ s->PutChar ('"');
+ }
+ }
+}
+
+#define DEPTH_INCREMENT 2
+void
+lldb_private::Type::DumpValue
+(
+ ExecutionContext *exe_ctx,
+ clang::ASTContext *ast_context,
+ void *clang_type,
+ Stream *s,
+ lldb::Format format,
+ const lldb_private::DataExtractor &data,
+ uint32_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
+)
+{
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
+ switch (qual_type->getTypeClass())
+ {
+ case clang::Type::Record:
+ {
+ const clang::RecordType *record_type = cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ uint32_t field_bit_offset = 0;
+ uint32_t field_byte_offset = 0;
+ const clang::ASTRecordLayout &record_layout = ast_context->getASTRecordLayout(record_decl);
+ uint32_t child_idx = 0;
+
+
+ const clang::CXXRecordDecl *cxx_record_decl = dyn_cast<clang::CXXRecordDecl>(record_decl);
+ if (cxx_record_decl)
+ {
+ // We might have base classes to print out first
+ clang::CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end;
+ ++base_class)
+ {
+ const clang::CXXRecordDecl *base_class_decl = cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::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);
+ else
+ field_bit_offset = record_layout.getBaseClassOffset(base_class_decl);
+ field_byte_offset = field_bit_offset / 8;
+ assert (field_bit_offset % 8 == 0);
+ if (child_idx == 0)
+ s->PutChar('{');
+ else
+ s->PutChar(',');
+
+ clang::QualType base_class_qual_type = base_class->getType();
+ std::string base_class_type_name(base_class_qual_type.getAsString());
+
+ // Indent and print the base class type name
+ s->Printf("\n%*s%s ", depth + DEPTH_INCREMENT, "", base_class_type_name.c_str());
+
+ std::pair<uint64_t, unsigned> base_class_type_info = ast_context->getTypeInfo(base_class_qual_type);
+
+ // Dump the value of the member
+ Type::DumpValue (
+ exe_ctx,
+ ast_context, // The clang AST context for this type
+ base_class_qual_type.getAsOpaquePtr(),// The clang type we want to dump
+ s, // Stream to dump to
+ Type::GetFormat(base_class_qual_type.getAsOpaquePtr()), // 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;
+ }
+ }
+ const unsigned num_fields = record_layout.getFieldCount();
+
+ uint32_t field_idx = 0;
+ clang::RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx, ++child_idx)
+ {
+ // Print the starting squiggly bracket (if this is the
+ // 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, "");
+
+ clang::QualType field_type = field->getType();
+ // Print the member type if requested
+ // Figure out the type byte size (field_type_info.first) and
+ // alignment (field_type_info.second) from the AST context.
+ std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(field_type);
+ assert(field_idx < num_fields);
+ // 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 (ast_context, *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
+ Type::DumpValue (
+ exe_ctx,
+ ast_context, // The clang AST context for this type
+ field_type.getAsOpaquePtr(), // The clang type we want to dump
+ s, // Stream to dump to
+ Type::GetFormat(field_type.getAsOpaquePtr()), // 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:
+ {
+ const clang::EnumType *enum_type = cast<clang::EnumType>(qual_type.getTypePtr());
+ const clang::EnumDecl *enum_decl = enum_type->getDecl();
+ assert(enum_decl);
+ clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
+ uint32_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->getNameAsCString());
+ return;
+ }
+ }
+ // If we have gotten here we didn't get find the enumerator in the
+ // enum decl, so just print the integer.
+ s->Printf("%lli", enum_value);
+ }
+ return;
+
+ case clang::Type::ConstantArray:
+ {
+ const clang::ConstantArrayType *array = cast<clang::ConstantArrayType>(qual_type.getTypePtr());
+ bool is_array_of_characters = false;
+ clang::QualType element_qual_type = array->getElementType();
+
+ 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 = ast_context->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
+ {
+ lldb::Format element_format = Type::GetFormat(element_qual_type.getAsOpaquePtr());
+
+ 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
+ Type::DumpValue (
+ exe_ctx,
+ ast_context, // The clang AST context for this type
+ element_qual_type.getAsOpaquePtr(), // The clang type we want to dump
+ 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:
+ {
+ clang::QualType typedef_qual_type = cast<clang::TypedefType>(qual_type)->LookThroughTypedefs();
+ lldb::Format typedef_format = lldb_private::Type::GetFormat(typedef_qual_type.getAsOpaquePtr());
+ std::pair<uint64_t, unsigned> typedef_type_info = ast_context->getTypeInfo(typedef_qual_type);
+ uint64_t typedef_byte_size = typedef_type_info.first / 8;
+
+ return Type::DumpValue(
+ exe_ctx,
+ ast_context, // The clang AST context for this type
+ typedef_qual_type.getAsOpaquePtr(), // The clang type we want to dump
+ 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;
+
+ 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)
+ Type::DumpSummary (exe_ctx, ast_context, clang_type, s, data, data_byte_offset, data_byte_size);
+ break;
+ }
+}
+
+bool
+lldb_private::Type::DumpTypeValue
+(
+ Stream *s,
+ clang::ASTContext *ast_context,
+ void *clang_type,
+ lldb::Format format,
+ const lldb_private::DataExtractor &data,
+ uint32_t byte_offset,
+ size_t byte_size,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset
+)
+{
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
+ if (ClangASTContext::IsAggregateType (clang_type))
+ {
+ return 0;
+ }
+ else
+ {
+ switch (qual_type->getTypeClass())
+ {
+ case clang::Type::Enum:
+ {
+ const clang::EnumType *enum_type = cast<clang::EnumType>(qual_type.getTypePtr());
+ const clang::EnumDecl *enum_decl = enum_type->getDecl();
+ assert(enum_decl);
+ clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
+ uint32_t offset = byte_offset;
+ const int64_t enum_value = 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() == enum_value)
+ {
+ s->PutCString (enum_pos->getNameAsCString());
+ 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("%lli", enum_value);
+ return true;
+ }
+ break;
+
+ case clang::Type::Typedef:
+ {
+ clang::QualType typedef_qual_type = cast<clang::TypedefType>(qual_type)->LookThroughTypedefs();
+ lldb::Format typedef_format = Type::GetFormat(typedef_qual_type.getAsOpaquePtr());
+ std::pair<uint64_t, unsigned> typedef_type_info = ast_context->getTypeInfo(typedef_qual_type);
+ uint64_t typedef_byte_size = typedef_type_info.first / 8;
+
+ return Type::DumpTypeValue(
+ s,
+ ast_context, // The clang AST context for this type
+ typedef_qual_type.getAsOpaquePtr(), // The clang type we want to dump
+ typedef_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
+ }
+ break;
+
+ default:
+ // We are down the a scalar type that we just need to display.
+ return data.Dump(s,
+ byte_offset,
+ format,
+ byte_size,
+ 1,
+ UINT32_MAX,
+ LLDB_INVALID_ADDRESS,
+ bitfield_bit_size,
+ bitfield_bit_offset);
+ break;
+ }
+ }
+ return 0;
+}
+
+bool
+lldb_private::Type::GetValueAsScalar
+(
+ clang::ASTContext *ast_context,
+ void *clang_type,
+ const lldb_private::DataExtractor &data,
+ uint32_t data_byte_offset,
+ size_t data_byte_size,
+ Scalar &value
+)
+{
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
+
+ if (ClangASTContext::IsAggregateType (clang_type))
+ {
+ return false; // Aggregate types don't have scalar values
+ }
+ else
+ {
+ uint32_t count = 0;
+ lldb::Encoding encoding = Type::GetEncoding (clang_type, count);
+
+ if (encoding == lldb::eEncodingInvalid || count != 1)
+ return false;
+
+ uint64_t bit_width = ast_context->getTypeSize(qual_type);
+ uint32_t byte_size = (bit_width + 7 ) / 8;
+ uint32_t offset = data_byte_offset;
+ switch (encoding)
+ {
+ 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 = (int64_t)data.GetMaxU64 (&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
+lldb_private::Type::SetValueFromScalar
+(
+ clang::ASTContext *ast_context,
+ void *clang_type,
+ const Scalar &value,
+ Stream &strm
+)
+{
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
+
+ // Aggregate types don't have scalar values
+ if (!ClangASTContext::IsAggregateType (clang_type))
+ {
+ strm.GetFlags().Set(Stream::eBinary);
+ uint32_t count = 0;
+ lldb::Encoding encoding = Type::GetEncoding (clang_type, count);
+
+ if (encoding == lldb::eEncodingInvalid || count != 1)
+ return false;
+
+ uint64_t bit_width = ast_context->getTypeSize(qual_type);
+ // This function doesn't currently handle non-byte aligned assignments
+ if ((bit_width % 8) != 0)
+ return false;
+
+ uint32_t byte_size = (bit_width + 7 ) / 8;
+ switch (encoding)
+ {
+ 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;
+}
+
+
+uint64_t
+lldb_private::Type::GetByteSize()
+{
+ if (m_byte_size == 0)
+ {
+ switch (m_encoding_uid_type)
+ {
+ case eIsTypeWithUID:
+ case eIsConstTypeWithUID:
+ case eIsRestrictTypeWithUID:
+ case eIsVolatileTypeWithUID:
+ case eTypedefToTypeWithUID:
+ if (m_encoding_uid != LLDB_INVALID_UID)
+ {
+ Type *encoding_type = m_symbol_file->ResolveTypeUID (m_encoding_uid);
+ if (encoding_type)
+ m_byte_size = encoding_type->GetByteSize();
+ }
+ if (m_byte_size == 0)
+ {
+ uint64_t bit_width = GetClangAST()->getTypeSize(clang::QualType::getFromOpaquePtr(GetOpaqueClangQualType()));
+ m_byte_size = (bit_width + 7 ) / 8;
+ }
+ break;
+
+ // If we are a pointer or reference, then this is just a pointer size;
+ case ePointerToTypeWithUID:
+ case eLValueReferenceToTypeWithUID:
+ case eRValueReferenceToTypeWithUID:
+ m_byte_size = GetTypeList()->GetClangASTContext().GetPointerBitSize() / 8;
+ break;
+ }
+ }
+ return m_byte_size;
+}
+
+
+uint32_t
+lldb_private::Type::GetNumChildren (bool omit_empty_base_classes)
+{
+ if (!ResolveClangType())
+ return 0;
+ return ClangASTContext::GetNumChildren (m_clang_qual_type, omit_empty_base_classes);
+
+}
+
+bool
+lldb_private::Type::IsAggregateType ()
+{
+ if (ResolveClangType())
+ return ClangASTContext::IsAggregateType (m_clang_qual_type);
+ return false;
+}
+
+lldb::Format
+lldb_private::Type::GetFormat ()
+{
+ // Make sure we resolve our type if it already hasn't been.
+ if (!ResolveClangType())
+ return lldb::eFormatInvalid;
+ return lldb_private::Type::GetFormat (m_clang_qual_type);
+}
+
+
+lldb::Format
+lldb_private::Type::GetFormat (void *clang_type)
+{
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
+
+ switch (qual_type->getTypeClass())
+ {
+ 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:
+ break;
+
+ case clang::Type::Builtin:
+ switch (cast<clang::BuiltinType>(qual_type)->getKind())
+ {
+ default: assert(0 && "Unknown builtin type!");
+ case clang::BuiltinType::Void:
+ break;
+
+ case clang::BuiltinType::Bool: return lldb::eFormatBoolean;
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::WChar: return lldb::eFormatChar;
+ case clang::BuiltinType::Char16: return lldb::eFormatUnicode16;
+ case clang::BuiltinType::Char32: return lldb::eFormatUnicode32;
+ case clang::BuiltinType::UShort: return lldb::eFormatHex;
+ case clang::BuiltinType::Short: return lldb::eFormatDecimal;
+ case clang::BuiltinType::UInt: return lldb::eFormatHex;
+ case clang::BuiltinType::Int: return lldb::eFormatDecimal;
+ case clang::BuiltinType::ULong: return lldb::eFormatHex;
+ case clang::BuiltinType::Long: return lldb::eFormatDecimal;
+ case clang::BuiltinType::ULongLong: return lldb::eFormatHex;
+ case clang::BuiltinType::LongLong: return lldb::eFormatDecimal;
+ case clang::BuiltinType::UInt128: return lldb::eFormatHex;
+ case clang::BuiltinType::Int128: return lldb::eFormatDecimal;
+ case clang::BuiltinType::Float: return lldb::eFormatFloat;
+ case clang::BuiltinType::Double: return lldb::eFormatFloat;
+ case clang::BuiltinType::LongDouble: return lldb::eFormatFloat;
+ case clang::BuiltinType::NullPtr: 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: return lldb::eFormatComplex;
+ case clang::Type::ObjCInterface: break;
+ case clang::Type::Record: break;
+ case clang::Type::Enum: return lldb::eFormatEnum;
+ case clang::Type::Typedef:
+ return lldb_private::Type::GetFormat(cast<clang::TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr());
+
+ case clang::Type::TypeOfExpr:
+ case clang::Type::TypeOf:
+ case clang::Type::Decltype:
+// case clang::Type::QualifiedName:
+ case clang::Type::TemplateSpecialization: break;
+ }
+ // We don't know hot to display this type...
+ return lldb::eFormatBytes;
+}
+
+
+lldb::Encoding
+lldb_private::Type::GetEncoding (uint32_t &count)
+{
+ // Make sure we resolve our type if it already hasn't been.
+ if (!ResolveClangType())
+ return lldb::eEncodingInvalid;
+
+ return Type::GetEncoding (m_clang_qual_type, count);
+}
+
+
+lldb::Encoding
+lldb_private::Type::GetEncoding (void *clang_type, uint32_t &count)
+{
+ count = 1;
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
+
+ switch (qual_type->getTypeClass())
+ {
+ 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<clang::BuiltinType>(qual_type)->getKind())
+ {
+ default: assert(0 && "Unknown builtin type!");
+ case clang::BuiltinType::Void:
+ break;
+
+ case clang::BuiltinType::Bool:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::Int128: return lldb::eEncodingSint;
+
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::UInt128: return lldb::eEncodingUint;
+
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::LongDouble: return lldb::eEncodingIEEE754;
+
+ case clang::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;
+ // Complex numbers are made up of floats
+ case clang::Type::Complex:
+ count = 2;
+ return lldb::eEncodingIEEE754;
+
+ case clang::Type::ObjCInterface: break;
+ case clang::Type::Record: break;
+ case clang::Type::Enum: return lldb::eEncodingSint;
+ case clang::Type::Typedef:
+ return Type::GetEncoding(cast<clang::TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), count);
+ break;
+
+ case clang::Type::TypeOfExpr:
+ case clang::Type::TypeOf:
+ case clang::Type::Decltype:
+// case clang::Type::QualifiedName:
+ case clang::Type::TemplateSpecialization: break;
+ }
+ count = 0;
+ return lldb::eEncodingInvalid;
+}
+
+
+bool
+lldb_private::Type::DumpValueInMemory
+(
+ lldb_private::ExecutionContext *exe_ctx,
+ lldb_private::Stream *s,
+ lldb::addr_t address,
+ lldb::AddressType address_type,
+ bool show_types,
+ bool show_summary,
+ bool verbose
+)
+{
+ if (address != LLDB_INVALID_ADDRESS)
+ {
+ lldb_private::DataExtractor data;
+ data.SetByteOrder (exe_ctx->process->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
+lldb_private::Type::ReadFromMemory
+(
+ lldb_private::ExecutionContext *exe_ctx,
+ clang::ASTContext *ast_context,
+ void *clang_type,
+ lldb::addr_t addr,
+ lldb::AddressType address_type,
+ lldb_private::DataExtractor &data
+)
+{
+ if (address_type == lldb::eAddressTypeFile)
+ {
+ // Can't convert a file address to anything valid without more
+ // context (which Module it came from)
+ return false;
+ }
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
+
+ const uint32_t byte_size = (ast_context->getTypeSize (qual_type) + 7) / 8;
+ 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 == lldb::eAddressTypeHost)
+ {
+ // The address is an address in this process, so just copy it
+ memcpy (dst, (uint8_t*)NULL + addr, byte_size);
+ return true;
+ }
+ else
+ {
+ if (exe_ctx && exe_ctx->process)
+ {
+ Error error;
+ return exe_ctx->process->ReadMemory(addr, dst, byte_size, error) == byte_size;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+lldb_private::Type::WriteToMemory
+(
+ lldb_private::ExecutionContext *exe_ctx,
+ clang::ASTContext *ast_context,
+ void *clang_type,
+ lldb::addr_t addr,
+ lldb::AddressType address_type,
+ StreamString &new_value
+)
+{
+ if (address_type == lldb::eAddressTypeFile)
+ {
+ // Can't convert a file address to anything valid without more
+ // context (which Module it came from)
+ return false;
+ }
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
+ const uint32_t byte_size = (ast_context->getTypeSize (qual_type) + 7) / 8;
+
+ if (byte_size > 0)
+ {
+ if (address_type == lldb::eAddressTypeHost)
+ {
+ // The address is an address in this process, so just copy it
+ memcpy ((void *)addr, new_value.GetData(), byte_size);
+ return true;
+ }
+ else
+ {
+ if (exe_ctx && exe_ctx->process)
+ {
+ Error error;
+ return exe_ctx->process->WriteMemory(addr, new_value.GetData(), byte_size, error) == byte_size;
+ }
+ }
+ }
+ return false;
+}
+
+
+bool
+lldb_private::Type::ReadFromMemory (lldb_private::ExecutionContext *exe_ctx, lldb::addr_t addr, lldb::AddressType address_type, lldb_private::DataExtractor &data)
+{
+ if (address_type == lldb::eAddressTypeFile)
+ {
+ // Can't convert a file address to anything valid without more
+ // context (which Module it came from)
+ return false;
+ }
+
+ const uint32_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 == lldb::eAddressTypeHost)
+ {
+ // The address is an address in this process, so just copy it
+ memcpy (dst, (uint8_t*)NULL + addr, byte_size);
+ return true;
+ }
+ else
+ {
+ if (exe_ctx && exe_ctx->process)
+ {
+ Error error;
+ return exe_ctx->process->ReadMemory(addr, dst, byte_size, error) == byte_size;
+ }
+ }
+ }
+ return false;
+}
+
+
+bool
+lldb_private::Type::WriteToMemory (lldb_private::ExecutionContext *exe_ctx, lldb::addr_t addr, lldb::AddressType address_type, lldb_private::DataExtractor &data)
+{
+ return false;
+}
+
+
+lldb_private::TypeList*
+lldb_private::Type::GetTypeList()
+{
+ return GetSymbolFile()->GetObjectFile()->GetModule()->GetTypeList();
+}
+
+
+bool
+lldb_private::Type::ResolveClangType()
+{
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(m_clang_qual_type));
+ if (qual_type.getTypePtr() == NULL)
+ {
+ clang::QualType resolved_qual_type;
+ TypeList *type_list = GetTypeList();
+ if (m_encoding_uid != LLDB_INVALID_UID)
+ {
+ Type *encoding_type = m_symbol_file->ResolveTypeUID(m_encoding_uid);
+ if (encoding_type)
+ {
+
+ switch (m_encoding_uid_type)
+ {
+ case eIsTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(encoding_type->GetOpaqueClangQualType());
+ break;
+
+ case eIsConstTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(ClangASTContext::AddConstModifier (encoding_type->GetOpaqueClangQualType()));
+ break;
+
+ case eIsRestrictTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(ClangASTContext::AddRestrictModifier (encoding_type->GetOpaqueClangQualType()));
+ break;
+
+ case eIsVolatileTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(ClangASTContext::AddVolatileModifier (encoding_type->GetOpaqueClangQualType()));
+ break;
+
+ case eTypedefToTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->CreateClangTypedefType (this, encoding_type));
+ // Clear the name so it can get fully qualified in case the
+ // typedef is in a namespace.
+ m_name.Clear();
+ break;
+
+ case ePointerToTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->CreateClangPointerType (encoding_type));
+ break;
+
+ case eLValueReferenceToTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->CreateClangLValueReferenceType (encoding_type));
+ break;
+
+ case eRValueReferenceToTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->CreateClangRValueReferenceType (encoding_type));
+ break;
+
+ default:
+ assert(!"Unhandled encoding_uid_type.");
+ break;
+ }
+ }
+ }
+ else
+ {
+ // We have no encoding type, return void?
+ void *void_clang_type = type_list->GetClangASTContext().GetVoidBuiltInType();
+ switch (m_encoding_uid_type)
+ {
+ case eIsTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(void_clang_type);
+ break;
+
+ case eIsConstTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr (ClangASTContext::AddConstModifier (void_clang_type));
+ break;
+
+ case eIsRestrictTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr (ClangASTContext::AddRestrictModifier (void_clang_type));
+ break;
+
+ case eIsVolatileTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr (ClangASTContext::AddVolatileModifier (void_clang_type));
+ break;
+
+ case eTypedefToTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->GetClangASTContext().CreateTypedefType (m_name.AsCString(), void_clang_type, NULL));
+ break;
+
+ case ePointerToTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->GetClangASTContext().CreatePointerType (void_clang_type));
+ break;
+
+ case eLValueReferenceToTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->GetClangASTContext().CreateLValueReferenceType (void_clang_type));
+ break;
+
+ case eRValueReferenceToTypeWithUID:
+ resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->GetClangASTContext().CreateRValueReferenceType (void_clang_type));
+ break;
+
+ default:
+ assert(!"Unhandled encoding_uid_type.");
+ break;
+ }
+ }
+ if (resolved_qual_type.getTypePtr())
+ {
+ m_clang_qual_type = resolved_qual_type.getAsOpaquePtr();
+ }
+
+ }
+ return m_clang_qual_type != NULL;
+}
+
+void *
+lldb_private::Type::GetChildClangTypeAtIndex
+(
+ const char *parent_name,
+ uint32_t idx,
+ bool transparent_pointers,
+ bool omit_empty_base_classes,
+ ConstString& name,
+ uint32_t &child_byte_size,
+ int32_t &child_byte_offset,
+ uint32_t &child_bitfield_bit_size,
+ uint32_t &child_bitfield_bit_offset
+)
+{
+ if (!ResolveClangType())
+ return false;
+
+ std::string name_str;
+ void *child_qual_type = GetClangASTContext().GetChildClangTypeAtIndex (
+ parent_name,
+ m_clang_qual_type,
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ name_str,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset);
+
+ if (child_qual_type)
+ {
+ if (!name_str.empty())
+ name.SetCString(name_str.c_str());
+ else
+ name.Clear();
+ }
+ return child_qual_type;
+}
+
+
+
+void *
+lldb_private::Type::GetOpaqueClangQualType ()
+{
+ ResolveClangType();
+ return m_clang_qual_type;
+}
+
+clang::ASTContext *
+lldb_private::Type::GetClangAST ()
+{
+ TypeList *type_list = GetTypeList();
+ if (type_list)
+ return type_list->GetClangASTContext().getASTContext();
+ return NULL;
+}
+
+lldb_private::ClangASTContext &
+lldb_private::Type::GetClangASTContext ()
+{
+ return GetTypeList()->GetClangASTContext();
+}
+
+int
+lldb_private::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;
+}
+
diff --git a/lldb/source/Symbol/TypeList.cpp b/lldb/source/Symbol/TypeList.cpp
new file mode 100644
index 00000000000..f037035ed21
--- /dev/null
+++ b/lldb/source/Symbol/TypeList.cpp
@@ -0,0 +1,239 @@
+//===-- 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/ClangASTContext.h"
+#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(const char *target_triple) :
+ m_types(),
+ m_ast(target_triple)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+TypeList::~TypeList()
+{
+}
+
+//----------------------------------------------------------------------
+// Add a base type to the type list
+//----------------------------------------------------------------------
+
+//struct CampareDCTypeBaton
+//{
+// CampareDCTypeBaton(const std::vector<TypeSP>& _types, const Type* _search_type) :
+// types(_types),
+// search_type(_search_type)
+// {
+// }
+// const std::vector<TypeSP>& types;
+// const Type* search_type;
+//};
+//
+//static int
+//compare_dc_type (const void *key, const void *arrmem)
+//{
+// const Type* search_type = ((CampareDCTypeBaton*) key)->search_type;
+// uint32_t curr_index = *(uint32_t *)arrmem;
+// const Type* curr_type = ((CampareDCTypeBaton*) key)->types[curr_index].get();
+// Type::CompareState state;
+// return Type::Compare(*search_type, *curr_type, state);
+//}
+//
+//struct LessThanBinaryPredicate
+//{
+// LessThanBinaryPredicate(const CampareDCTypeBaton& _compare_baton) :
+// compare_baton(_compare_baton)
+// {
+// }
+//
+// bool operator() (uint32_t a, uint32_t b) const
+// {
+// Type::CompareState state;
+// return Type::Compare(*compare_baton.search_type, *compare_baton.types[b].get(), state) < 0;
+// }
+// const CampareDCTypeBaton& compare_baton;
+//};
+
+TypeSP
+TypeList::InsertUnique(TypeSP& type_sp)
+{
+#if 0
+// Stream s(stdout);
+// s << "TypeList::InsertUnique for type ";
+// type_sp->Dump(s);
+// s << "Current list:\n";
+// Dump(s);
+
+ CampareDCTypeBaton compare_baton(m_types, type_sp.get());
+ uint32_t* match_index_ptr = (uint32_t*)bsearch(&compare_baton, &m_sorted_indexes[0], m_sorted_indexes.size(), sizeof(uint32_t), compare_dc_type);
+ if (match_index_ptr)
+ {
+// s << "returning existing type: " << (void *)m_types[*match_index_ptr].get() << "\n";
+ return m_types[*match_index_ptr];
+ }
+
+ // Get the new index within the m_types array before we add the new type
+ uint32_t uniqued_type_index = m_types.size();
+ // Add the new shared pointer to our type by appending it to the end of the types array
+ m_types.push_back(type_sp);
+ // Figure out what the sorted index of this new type should be
+ uint32_t fake_index = 0;
+ LessThanBinaryPredicate compare_func_obj(compare_baton);
+ std::vector<uint32_t>::iterator insert_pos = std::upper_bound(m_sorted_indexes.begin(), m_sorted_indexes.end(), fake_index, compare_func_obj);
+ // Insert the sorted index into our sorted index array
+ m_sorted_indexes.insert(insert_pos, uniqued_type_index);
+#else
+ // Just push each type on the back for now. We will worry about uniquing later
+ m_types.push_back (type_sp);
+#endif
+// s << "New list:\n";
+// Dump(s);
+
+ return type_sp;
+}
+
+//----------------------------------------------------------------------
+// Find a base type by its unique ID.
+//----------------------------------------------------------------------
+TypeSP
+TypeList::FindType(lldb::user_id_t uid)
+{
+ TypeSP type_sp;
+ iterator pos, end;
+ for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
+ if ((*pos)->GetID() == uid)
+ return *pos;
+
+ return type_sp;
+}
+
+//----------------------------------------------------------------------
+// Find a type by name.
+//----------------------------------------------------------------------
+TypeList
+TypeList::FindTypes(const ConstString &name)
+{
+ 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)->GetName() == name)
+ types.InsertUnique(*pos);
+ return types;
+}
+
+void
+TypeList::Clear()
+{
+ m_types.clear();
+}
+
+uint32_t
+TypeList::GetSize() const
+{
+ return m_types.size();
+}
+
+TypeSP
+TypeList::GetTypeAtIndex(uint32_t idx)
+{
+ TypeSP type_sp;
+ if (idx < m_types.size())
+ type_sp = m_types[idx];
+ return type_sp;
+}
+
+void
+TypeList::Dump(Stream *s, bool show_context)
+{
+// std::vector<uint32_t>::const_iterator pos, end;
+// for (pos = end = m_sorted_indexes.begin(), end = m_sorted_indexes.end(); pos != end; ++pos)
+// {
+// m_types[*pos]->Dump(s, show_context);
+// }
+
+ m_ast.getASTContext()->getTranslationUnitDecl()->print(llvm::fouts(), 0);
+ const size_t num_types = m_types.size();
+ for (size_t i=0; i<num_types; ++i)
+ {
+ m_types[i]->Dump(s, show_context);
+ }
+// ASTContext *ast_context = GetClangASTContext ().getASTContext();
+// if (ast_context)
+// ast_context->PrintStats();
+}
+
+
+ClangASTContext &
+TypeList::GetClangASTContext ()
+{
+ return m_ast;
+}
+
+void *
+TypeList::CreateClangPointerType (Type *type)
+{
+ assert(type);
+ return m_ast.CreatePointerType(type->GetOpaqueClangQualType());
+}
+
+void *
+TypeList::CreateClangTypedefType (Type *typedef_type, Type *base_type)
+{
+ assert(typedef_type && base_type);
+ return m_ast.CreateTypedefType(typedef_type->GetName().AsCString(), base_type->GetOpaqueClangQualType(), typedef_type->GetSymbolFile()->GetClangDeclContextForTypeUID(typedef_type->GetID()));
+}
+
+void *
+TypeList::CreateClangLValueReferenceType (Type *type)
+{
+ assert(type);
+ return m_ast.CreateLValueReferenceType(type->GetOpaqueClangQualType());
+}
+
+void *
+TypeList::CreateClangRValueReferenceType (Type *type)
+{
+ assert(type);
+ return m_ast.CreateRValueReferenceType (type->GetOpaqueClangQualType());
+}
+
+
+
diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp
new file mode 100644
index 00000000000..35dcabfdd59
--- /dev/null
+++ b/lldb/source/Symbol/Variable.cpp
@@ -0,0 +1,167 @@
+//===-- 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/Stream.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Variable constructor
+//----------------------------------------------------------------------
+Variable::Variable(lldb::user_id_t uid,
+ const ConstString& name,
+ Type *type,
+ ValueType scope,
+ SymbolContextScope *context,
+ Declaration* decl_ptr,
+ const DWARFExpression& location,
+ bool external,
+ bool artificial) :
+ UserID(uid),
+ m_name(name),
+ m_type(type),
+ m_scope(scope),
+ m_context(context),
+ m_declaration(decl_ptr),
+ m_location(location),
+ m_external(external),
+ m_artificial(artificial)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Variable::~Variable()
+{
+}
+
+
+void
+Variable::Dump(Stream *s, bool show_context) const
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ *s << "Variable" << (const UserID&)*this;
+
+ if (m_name)
+ *s << ", name = \"" << m_name << "\"";
+
+ if (m_type != NULL)
+ {
+ *s << ", type = " << (void*)m_type << " (";
+ m_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_context != NULL)
+ {
+ s->PutCString(", context = ( ");
+ m_context->DumpSymbolContext(s);
+ s->PutCString(" )");
+ }
+
+ m_declaration.Dump(s);
+
+ if (m_location.IsValid())
+ {
+ s->PutCString(", location = ");
+ m_location.GetDescription(s, lldb::eDescriptionLevelBrief);
+ }
+
+ if (m_external)
+ s->PutCString(", external");
+
+ if (m_artificial)
+ s->PutCString(", artificial");
+
+ s->EOL();
+}
+
+
+size_t
+Variable::MemorySize() const
+{
+ return sizeof(Variable);
+}
+
+
+void
+Variable::CalculateSymbolContext (SymbolContext *sc)
+{
+ if (m_context)
+ m_context->CalculateSymbolContext(sc);
+ else
+ sc->Clear();
+}
+
+
+bool
+Variable::IsInScope (StackFrame *frame)
+{
+ switch (m_scope)
+ {
+ case eValueTypeVariableGlobal:
+ // Globals and statics are always in scope.
+ return true;
+
+ case eValueTypeVariableArgument:
+ case eValueTypeVariableLocal:
+ // Check if the location has a location list that describes the value
+ // of the variable with address ranges and different locations for each
+ // address range?
+ if (m_location.IsLocationList())
+ {
+ // 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.LocationListContainsLoadAddress (&frame->GetThread().GetProcess(), frame->GetPC());
+ }
+ else
+ {
+ // We don't have a location list, we just need to see if the block
+ // that this variable was defined in is currently
+ Block *frame_block = frame->GetSymbolContext(eSymbolContextBlock).block;
+ if (frame_block)
+ {
+ SymbolContext variable_sc;
+ CalculateSymbolContext (&variable_sc);
+ if (variable_sc.function && variable_sc.block)
+ return variable_sc.block->ContainsBlockWithID (frame_block->GetID());
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
diff --git a/lldb/source/Symbol/VariableList.cpp b/lldb/source/Symbol/VariableList.cpp
new file mode 100644
index 00000000000..7f864f287ea
--- /dev/null
+++ b/lldb/source/Symbol/VariableList.cpp
@@ -0,0 +1,116 @@
+//===-- 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/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(VariableSP &variable_sp)
+{
+ m_variables.push_back(variable_sp);
+}
+
+
+void
+VariableList::AddVariables(VariableList *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(uint32_t idx)
+{
+ VariableSP variable_sp;
+ if (idx < m_variables.size())
+ variable_sp = m_variables[idx];
+ return variable_sp;
+}
+
+
+
+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)->GetName() == name)
+ {
+ var_sp = (*pos);
+ break;
+ }
+ }
+ return var_sp;
+}
+
+
+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/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp
new file mode 100644
index 00000000000..20d35e3dbb0
--- /dev/null
+++ b/lldb/source/Target/ABI.cpp
@@ -0,0 +1,47 @@
+//===-- 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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ABI*
+ABI::FindPlugin (const ConstString &triple)
+{
+ std::auto_ptr<ABI> abi_ap;
+ ABICreateInstance create_callback;
+
+ for (uint32_t idx = 0;
+ (create_callback = PluginManager::GetABICreateCallbackAtIndex(idx)) != NULL;
+ ++idx)
+ {
+ abi_ap.reset (create_callback(triple));
+
+ if (abi_ap.get())
+ return abi_ap.release();
+ }
+
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+ABI::ABI()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ABI::~ABI()
+{
+}
diff --git a/lldb/source/Target/ExecutionContext.cpp b/lldb/source/Target/ExecutionContext.cpp
new file mode 100644
index 00000000000..e79f8c243ef
--- /dev/null
+++ b/lldb/source/Target/ExecutionContext.cpp
@@ -0,0 +1,107 @@
+//===-- 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/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() :
+ target (NULL),
+ process (NULL),
+ thread (NULL),
+ frame (NULL)
+{
+}
+
+ExecutionContext::ExecutionContext (Target* t, bool fill_current_process_thread_frame) :
+ target (t),
+ process (NULL),
+ thread (NULL),
+ frame (NULL)
+{
+ if (t && fill_current_process_thread_frame)
+ {
+ process = t->GetProcessSP().get();
+ if (process)
+ {
+ thread = process->GetThreadList().GetCurrentThread().get();
+ if (thread)
+ frame = thread->GetCurrentFrame().get();
+ }
+ }
+}
+
+ExecutionContext::ExecutionContext(Process* p, Thread *t, StackFrame *f) :
+ target (p ? &p->GetTarget() : NULL),
+ process (p),
+ thread (t),
+ frame (f)
+{
+}
+
+ExecutionContext::ExecutionContext (ExecutionContextScope *exe_scope_ptr)
+{
+ if (exe_scope_ptr)
+ exe_scope_ptr->Calculate (*this);
+ else
+ {
+ target = NULL;
+ process = NULL;
+ thread = NULL;
+ frame = NULL;
+ }
+}
+
+ExecutionContext::ExecutionContext (ExecutionContextScope &exe_scope_ref)
+{
+ exe_scope_ref.Calculate (*this);
+}
+
+void
+ExecutionContext::Clear()
+{
+ target = NULL;
+ process = NULL;
+ thread = NULL;
+ frame = NULL;
+}
+
+
+RegisterContext *
+ExecutionContext::GetRegisterContext () const
+{
+ if (frame)
+ return frame->GetRegisterContext();
+ else if (thread)
+ return thread->GetRegisterContext();
+ return NULL;
+}
+
+ExecutionContextScope *
+ExecutionContext::GetBestExecutionContextScope () const
+{
+ if (frame)
+ return frame;
+ if (thread)
+ return thread;
+ if (process)
+ return process;
+ return target;
+}
diff --git a/lldb/source/Target/ObjCObjectPrinter.cpp b/lldb/source/Target/ObjCObjectPrinter.cpp
new file mode 100644
index 00000000000..81c73aa9581
--- /dev/null
+++ b/lldb/source/Target/ObjCObjectPrinter.cpp
@@ -0,0 +1,120 @@
+//===-- ObjCObjectPrinter.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/StreamString.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "ObjCObjectPrinter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ObjCObjectPrinter constructor
+//----------------------------------------------------------------------
+ObjCObjectPrinter::ObjCObjectPrinter (Process &process) :
+ m_process(process)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ObjCObjectPrinter::~ObjCObjectPrinter ()
+{
+}
+
+bool
+ObjCObjectPrinter::PrintObject (ConstString &str, Value &object_ptr, ExecutionContext &exe_ctx)
+{
+ if (!exe_ctx.process)
+ return false;
+
+ const Address *function_address = GetPrintForDebuggerAddr();
+
+ if (!function_address)
+ return false;
+
+ const char *target_triple = exe_ctx.process->GetTargetTriple().GetCString();
+ ClangASTContext *ast_context = exe_ctx.target->GetScratchClangASTContext();
+
+ void *return_qualtype = ast_context->GetCStringType(true);
+ Value ret;
+ ret.SetContext(Value::eContextTypeOpaqueClangQualType, return_qualtype);
+
+ ValueList arg_value_list;
+ arg_value_list.PushValue(object_ptr);
+
+ ClangFunction func(target_triple, ast_context, return_qualtype, *function_address, arg_value_list);
+ StreamString error_stream;
+
+ lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS;
+ func.InsertFunction(exe_ctx, wrapper_struct_addr, error_stream);
+ // FIXME: Check result of ExecuteFunction.
+ func.ExecuteFunction(exe_ctx, &wrapper_struct_addr, error_stream, true, 1000, true, ret);
+
+ addr_t result_ptr = ret.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+
+ // poor man's strcpy
+
+ size_t len = 0;
+ bool keep_reading = true;
+ Error error;
+ while (keep_reading)
+ {
+ char byte;
+
+ if (exe_ctx.process->ReadMemory(result_ptr + len, &byte, 1, error) != 1)
+ return false;
+
+ if (byte == '\0')
+ keep_reading = false;
+ else
+ ++len;
+ }
+
+ char desc[len + 1];
+
+ if (exe_ctx.process->ReadMemory(result_ptr, &desc[0], len + 1, error) != len + 1)
+ return false;
+
+ str.SetCString(desc);
+
+ return true;
+}
+
+Address *
+ObjCObjectPrinter::GetPrintForDebuggerAddr()
+{
+ if (!m_PrintForDebugger_addr.get())
+ {
+ ModuleList &modules = m_process.GetTarget().GetImages();
+
+ SymbolContextList contexts;
+ SymbolContext context;
+
+ if((!modules.FindSymbolsWithNameAndType(ConstString ("_NSPrintForDebugger"), eSymbolTypeCode, contexts)) &&
+ (!modules.FindSymbolsWithNameAndType(ConstString ("_CFPrintForDebugger"), eSymbolTypeCode, contexts)))
+ return NULL;
+
+ contexts.GetContextAtIndex(0, context);
+
+ m_PrintForDebugger_addr.reset(new Address(context.symbol->GetValue()));
+ }
+
+ return m_PrintForDebugger_addr.get();
+}
+
diff --git a/lldb/source/Target/PathMappingList.cpp b/lldb/source/Target/PathMappingList.cpp
new file mode 100644
index 00000000000..02ca0671ca0
--- /dev/null
+++ b/lldb/source/Target/PathMappingList.cpp
@@ -0,0 +1,125 @@
+//===-- 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
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+// Project includes
+#include "PathMappingList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// PathMappingList constructor
+//----------------------------------------------------------------------
+PathMappingList::PathMappingList
+(
+ ChangedCallback callback,
+ void *callback_baton
+) :
+ m_pairs (),
+ m_callback (callback),
+ m_callback_baton (callback_baton)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+PathMappingList::~PathMappingList ()
+{
+}
+
+void
+PathMappingList::Append (const ConstString &path,
+ const ConstString &replacement,
+ bool notify)
+{
+ m_pairs.push_back(pair(path, replacement));
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+}
+
+void
+PathMappingList::Insert (const ConstString &path,
+ const ConstString &replacement,
+ uint32_t index,
+ bool notify)
+{
+ 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::Remove (off_t index, bool notify)
+{
+ if (index >= m_pairs.size())
+ return false;
+
+ iterator iter = m_pairs.begin() + index;
+ m_pairs.erase(iter);
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+ return true;
+}
+
+void
+PathMappingList::Dump (Stream *s)
+{
+ unsigned int numPairs = m_pairs.size();
+ 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());
+ }
+}
+
+void
+PathMappingList::Clear (bool notify)
+{
+ m_pairs.clear();
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+}
+
+size_t
+PathMappingList::GetSize ()
+{
+ return m_pairs.size();
+}
+
+bool
+PathMappingList::RemapPath (const ConstString &path, ConstString &new_path)
+{
+ 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.GetCString(), 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;
+}
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
new file mode 100644
index 00000000000..9a6ab0c83e8
--- /dev/null
+++ b/lldb/source/Target/Process.cpp
@@ -0,0 +1,1876 @@
+//===-- 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/Target/Process.h"
+
+#include "lldb/lldb-private-log.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Process*
+Process::FindPlugin (Target &target, const char *plugin_name, Listener &listener)
+{
+ ProcessCreateInstance create_callback = NULL;
+ if (plugin_name)
+ {
+ create_callback = PluginManager::GetProcessCreateCallbackForPluginName (plugin_name);
+ if (create_callback)
+ {
+ std::auto_ptr<Process> debugger_ap(create_callback(target, listener));
+ if (debugger_ap->CanDebug(target))
+ return debugger_ap.release();
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; create_callback = PluginManager::GetProcessCreateCallbackAtIndex(idx); ++idx)
+ {
+ create_callback = PluginManager::GetProcessCreateCallbackAtIndex (idx);
+ if (create_callback)
+ {
+ std::auto_ptr<Process> debugger_ap(create_callback(target, listener));
+ if (debugger_ap->CanDebug(target))
+ return debugger_ap.release();
+ }
+ }
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Process constructor
+//----------------------------------------------------------------------
+Process::Process(Target &target, Listener &listener) :
+ UserID (LLDB_INVALID_PROCESS_ID),
+ Broadcaster ("Process"),
+ m_target (target),
+ m_section_load_info (),
+ m_public_state (eStateUnloaded),
+ m_private_state (eStateUnloaded),
+ m_private_state_broadcaster ("lldb.process.internal_state_broadcaster"),
+ m_private_state_control_broadcaster ("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_stop_id (0),
+ m_thread_index_id (0),
+ m_exit_status (-1),
+ m_exit_string (),
+ m_thread_list (this),
+ m_notifications (),
+ m_listener(listener),
+ m_unix_signals (),
+ m_objc_object_printer(*this)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Process::Process()", this);
+
+ listener.StartListeningForEvents (this,
+ eBroadcastBitStateChanged |
+ eBroadcastBitInterrupt |
+ eBroadcastBitSTDOUT |
+ eBroadcastBitSTDERR);
+
+ m_private_state_listener.StartListeningForEvents(&m_private_state_broadcaster,
+ eBroadcastBitStateChanged);
+
+ 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();
+}
+
+void
+Process::Finalize()
+{
+ // Do any cleanup needed prior to being destructed... Subclasses
+ // that override this method should call this superclass method as well.
+}
+
+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)
+{
+ StateType match_states[] = { eStateStopped, eStateCrashed, eStateDetached, eStateExited, eStateUnloaded };
+ return WaitForState (timeout, match_states, sizeof(match_states) / sizeof(StateType));
+}
+
+
+StateType
+Process::WaitForState
+(
+ const TimeValue *timeout,
+ const StateType *match_states, const uint32_t num_match_states
+)
+{
+ EventSP event_sp;
+ uint32_t i;
+ StateType state = eStateUnloaded;
+ while (state != eStateInvalid)
+ {
+ state = WaitForStateChangedEvents (timeout, event_sp);
+
+ for (i=0; i<num_match_states; ++i)
+ {
+ if (match_states[i] == state)
+ return state;
+ }
+ }
+ return state;
+}
+
+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,
+ event_sp))
+ state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ 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,
+ event_sp))
+ 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.
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ 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;
+}
+
+void
+Process::SetExitStatus (int status, const char *cstr)
+{
+ m_exit_status = status;
+ if (cstr)
+ m_exit_string = cstr;
+ else
+ m_exit_string.clear();
+
+ SetPrivateState (eStateExited);
+}
+
+// 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,
+ int signo, // Zero for no signal
+ int exit_status // Exit value of process if signal is zero
+)
+{
+ if (signo == 0 || exit_status)
+ {
+ TargetSP target_sp(Debugger::GetSharedInstance().GetTargetList().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;
+}
+
+
+uint32_t
+Process::GetNextThreadIndexID ()
+{
+ return ++m_thread_index_id;
+}
+
+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)
+{
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE);
+ if (log)
+ log->Printf("Process::SetPublicState (%s)", StateAsCString(new_state));
+ m_public_state.SetValue (new_state);
+}
+
+StateType
+Process::GetPrivateState ()
+{
+ return m_private_state.GetValue();
+}
+
+void
+Process::SetPrivateState (StateType new_state)
+{
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE);
+ bool state_changed = false;
+
+ if (log)
+ log->Printf("Process::SetPrivateState (%s)", StateAsCString(new_state));
+
+ Mutex::Locker locker(m_private_state.GetMutex());
+
+ const StateType old_state = m_private_state.GetValueNoLock ();
+ state_changed = old_state != new_state;
+ if (state_changed)
+ {
+ m_private_state.SetValueNoLock (new_state);
+ if (StateIsStoppedState(new_state))
+ {
+ m_stop_id++;
+ if (log)
+ log->Printf("Process::SetPrivateState (%s) stop_id = %u", StateAsCString(new_state), m_stop_id);
+ }
+ // Use our target to get a shared pointer to ourselves...
+ m_private_state_broadcaster.BroadcastEvent (eBroadcastBitStateChanged, new ProcessEventData (GetTarget().GetProcessSP(), new_state));
+ }
+ else
+ {
+ if (log)
+ log->Printf("Process::SetPrivateState (%s) state didn't change. Ignoring...", StateAsCString(new_state), StateAsCString(old_state));
+ }
+}
+
+
+uint32_t
+Process::GetStopID() const
+{
+ return m_stop_id;
+}
+
+addr_t
+Process::GetImageInfoAddress()
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
+DynamicLoader *
+Process::GetDynamicLoader()
+{
+ return NULL;
+}
+
+const ABI *
+Process::GetABI()
+{
+ ConstString& triple = m_target_triple;
+
+ if (triple.IsEmpty())
+ return NULL;
+
+ if (m_abi_sp.get() == NULL)
+ {
+ m_abi_sp.reset(ABI::FindPlugin(triple));
+ }
+
+ return m_abi_sp.get();
+}
+
+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.SetEnabledForAll (false);
+}
+
+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 = DisableBreakpoint (bp_site_sp.get());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid breakpoint site ID: %i", 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 = EnableBreakpoint (bp_site_sp.get());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid breakpoint site ID: %i", break_id);
+ }
+ return error;
+}
+
+lldb::user_id_t
+Process::CreateBreakpointSite (BreakpointLocationSP &owner, bool use_hardware)
+{
+ const addr_t load_addr = owner->GetAddress().GetLoadAddress (this);
+ 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, LLDB_INVALID_THREAD_ID, use_hardware));
+ if (bp_site_sp)
+ {
+ if (EnableBreakpoint (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)
+ {
+ DisableBreakpoint(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;
+ addr_t intersect_addr;
+ size_t intersect_size;
+ size_t opcode_offset;
+ size_t idx;
+ BreakpointSiteSP bp;
+
+ for (idx = 0; (bp = m_breakpoint_site_list.GetByIndex(idx)) != NULL; ++idx)
+ {
+ if (bp->GetType() == BreakpointSite::eSoftware)
+ {
+ if (bp->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->GetByteSize());
+ size_t buf_offset = intersect_addr - bp_addr;
+ ::memcpy(buf + buf_offset, bp->GetSavedOpcodeBytes() + opcode_offset, intersect_size);
+ }
+ }
+ }
+ return bytes_removed;
+}
+
+
+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%llx", bp_site->GetID(), (uint64_t)bp_addr);
+ if (bp_site->IsEnabled())
+ {
+ if (log)
+ log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%llx -- 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%llx.\n", 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%llx -- 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)
+ log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%llx -- 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 ("ProcessMacOSX::DisableBreakpoint (breakID = %d) addr = 0x%llx", 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[break_op_size];
+ 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[break_op_size];
+ // 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%llx -- 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%llx -- already disabled", bp_site->GetID(), (uint64_t)bp_addr);
+ return error;
+ }
+
+ if (log)
+ log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%llx -- FAILED: %s",
+ bp_site->GetID(),
+ (uint64_t)bp_addr,
+ error.AsCString());
+ return error;
+
+}
+
+
+size_t
+Process::ReadMemory (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;
+}
+
+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 (buf == NULL || size == 0)
+ return 0;
+ // 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::collection::const_iterator iter = m_breakpoint_site_list.GetMap()->lower_bound (addr);
+ BreakpointSiteList::collection::const_iterator end = m_breakpoint_site_list.GetMap()->end();
+
+ if (iter == end || iter->second->GetLoadAddress() > addr + size)
+ return DoWriteMemory(addr, buf, size, error);
+
+ BreakpointSiteList::collection::const_iterator pos;
+ size_t bytes_written = 0;
+ addr_t intersect_addr;
+ size_t intersect_size;
+ size_t opcode_offset;
+ const uint8_t *ubuf = (const uint8_t *)buf;
+
+ for (pos = iter; pos != end; ++pos)
+ {
+ BreakpointSiteSP bp;
+ bp = pos->second;
+
+ assert(bp->IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset));
+ 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.
+ break;
+ }
+ }
+
+ // 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;
+ }
+
+ // Write any remaining bytes after the last breakpoint if we have any left
+ if (bytes_written < size)
+ bytes_written += WriteMemoryPrivate (addr + bytes_written,
+ ubuf + bytes_written,
+ size - bytes_written,
+ error);
+
+ return bytes_written;
+}
+
+addr_t
+Process::AllocateMemory(size_t size, uint32_t permissions, Error &error)
+{
+ // Fixme: we should track the blocks we've allocated, and clean them up...
+ // We could even do our own allocator here if that ends up being more efficient.
+ return DoAllocateMemory (size, permissions, error);
+}
+
+Error
+Process::DeallocateMemory (addr_t ptr)
+{
+ return DoDeallocateMemory (ptr);
+}
+
+
+Error
+Process::EnableWatchpoint (WatchpointLocation *watchpoint)
+{
+ Error error;
+ error.SetErrorString("watchpoints are not supported");
+ return error;
+}
+
+Error
+Process::DisableWatchpoint (WatchpointLocation *watchpoint)
+{
+ 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)
+ {
+ // FIXME: Might want to put a timeout in here:
+ state = WaitForStateChangedEventsPrivate (NULL, event_sp);
+ if (state == eStateStopped || state == eStateCrashed || state == eStateExited)
+ break;
+ else
+ HandlePrivateEvent (event_sp);
+ }
+ return state;
+}
+
+Error
+Process::Launch
+(
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path
+)
+{
+ Error error;
+ m_target_triple.Clear();
+ m_abi_sp.reset();
+
+ Module *exe_module = m_target.GetExecutableModule().get();
+ if (exe_module)
+ {
+ char exec_file_path[PATH_MAX];
+ exe_module->GetFileSpec().GetPath(exec_file_path, sizeof(exec_file_path));
+ if (exe_module->GetFileSpec().Exists())
+ {
+ error = WillLaunch (exe_module);
+ if (error.Success())
+ {
+ // The args coming in should not contain the application name, the
+ // lldb_private::Process class will add this in case the executable
+ // gets resolved to a different file than was given on the command
+ // line (like when an applicaiton bundle is specified and will
+ // resolve to the contained exectuable file, or the file given was
+ // a symlink or other file system link that resolves to a different
+ // file).
+
+ // Get the resolved exectuable path
+
+ // Make a new argument vector
+ std::vector<const char *> exec_path_plus_argv;
+ // Append the resolved executable path
+ exec_path_plus_argv.push_back (exec_file_path);
+
+ // Push all args if there are any
+ if (argv)
+ {
+ for (int i = 0; argv[i]; ++i)
+ exec_path_plus_argv.push_back(argv[i]);
+ }
+
+ // Push a NULL to terminate the args.
+ exec_path_plus_argv.push_back(NULL);
+
+ // Now launch using these arguments.
+ error = DoLaunch (exe_module, exec_path_plus_argv.data(), envp, stdin_path, stdout_path, stderr_path);
+
+ 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;
+ StateType state = WaitForProcessStopPrivate(NULL, event_sp);
+
+ if (state == eStateStopped || state == eStateCrashed)
+ {
+ DidLaunch ();
+
+ // This delays passing the stopped event to listeners till DidLaunch gets
+ // a chance to complete...
+ HandlePrivateEvent (event_sp);
+ 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'.\n", exec_file_path);
+ }
+ }
+ return error;
+}
+
+Error
+Process::CompleteAttach ()
+{
+ Error error;
+ EventSP event_sp;
+ StateType state = WaitForProcessStopPrivate(NULL, event_sp);
+ if (state == eStateStopped || state == eStateCrashed)
+ {
+ DidAttach ();
+
+ // This delays passing the stopped event to listeners till DidLaunch gets
+ // a chance to complete...
+ HandlePrivateEvent(event_sp);
+ StartPrivateStateThread();
+ }
+ else
+ {
+ // We exited while trying to launch somehow. Don't call DidLaunch as that's
+ // not likely to work, and return an invalid pid.
+ if (state == eStateExited)
+ HandlePrivateEvent (event_sp);
+ error.SetErrorStringWithFormat("invalid state after attach: %s",
+ lldb_private::StateAsCString(state));
+ }
+ return error;
+}
+
+Error
+Process::Attach (lldb::pid_t attach_pid)
+{
+
+ m_target_triple.Clear();
+ m_abi_sp.reset();
+
+ Error error(WillAttach (attach_pid));
+ if (error.Success())
+ {
+ error = DoAttach (attach_pid);
+ if (error.Success())
+ {
+ error = CompleteAttach();
+ }
+ 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;
+}
+
+Error
+Process::Attach (const char *process_name, bool wait_for_launch)
+{
+ m_target_triple.Clear();
+ m_abi_sp.reset();
+
+ Error error (WillAttach (process_name, wait_for_launch));
+ if (error.Success())
+ {
+ StartPrivateStateThread();
+ error = DoAttach (process_name, wait_for_launch);
+ 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 = "attach failed";
+
+ SetExitStatus(-1, error_string);
+ }
+ }
+ else
+ {
+ error = CompleteAttach();
+ }
+ }
+ return error;
+}
+
+Error
+Process::Resume ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ log->Printf("Process::Resume() m_stop_id = %u", m_stop_id);
+
+ 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 to 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 suppoed to start back up with a signal.
+ if (m_thread_list.WillResume())
+ {
+ error = DoResume();
+ if (error.Success())
+ {
+ DidResume();
+ m_thread_list.DidResume();
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("thread list returned flase after WillResume");
+ }
+ }
+ return error;
+}
+
+Error
+Process::Halt ()
+{
+ Error error (WillHalt());
+
+ if (error.Success())
+ {
+ error = DoHalt();
+ if (error.Success())
+ DidHalt();
+ }
+ return error;
+}
+
+Error
+Process::Detach ()
+{
+ Error error (WillDetach());
+
+ if (error.Success())
+ {
+ DisableAllBreakpointSites();
+ error = DoDetach();
+ if (error.Success())
+ {
+ DidDetach();
+ StopPrivateStateThread();
+ }
+ }
+ return error;
+}
+
+Error
+Process::Destroy ()
+{
+ Error error (WillDestroy());
+ if (error.Success())
+ {
+ DisableAllBreakpointSites();
+ error = DoDestroy();
+ if (error.Success())
+ {
+ DidDestroy();
+ StopPrivateStateThread();
+ }
+ }
+ return error;
+}
+
+Error
+Process::Signal (int signal)
+{
+ Error error (WillSignal());
+ if (error.Success())
+ {
+ error = DoSignal(signal);
+ if (error.Success())
+ DidSignal();
+ }
+ return error;
+}
+
+UnixSignals &
+Process::GetUnixSignals ()
+{
+ return m_unix_signals;
+}
+
+Target &
+Process::GetTarget ()
+{
+ return m_target;
+}
+
+const Target &
+Process::GetTarget () const
+{
+ return m_target;
+}
+
+uint32_t
+Process::GetAddressByteSize()
+{
+ 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::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS);
+
+ switch (state)
+ {
+ 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_public_state.GetValue())
+ {
+ 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.
+ return_value = true;
+
+ // 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 also report it.
+ if (state != eStateInvalid)
+ {
+
+ RefreshStateAfterStop ();
+
+ if (m_thread_list.ShouldStop (event_ptr) == false)
+ {
+ switch (m_thread_list.ShouldReportStop (event_ptr))
+ {
+ case eVoteYes:
+ Process::ProcessEventData::SetRestartedInEvent (event_ptr, true);
+ case eVoteNoOpinion:
+ return_value = true;
+ break;
+ case eVoteNo:
+ return_value = false;
+ break;
+ }
+
+ if (log)
+ log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process", event_ptr, StateAsCString(state));
+ Resume ();
+ }
+ else
+ {
+ return_value = true;
+ SynchronouslyNotifyStateChanged (state);
+ }
+ }
+ }
+ }
+
+ if (log)
+ log->Printf ("Process::ShouldBroadcastEvent (%p) => %s", event_ptr, StateAsCString(state), return_value ? "YES" : "NO");
+ return return_value;
+}
+
+//------------------------------------------------------------------
+// Thread Queries
+//------------------------------------------------------------------
+
+ThreadList &
+Process::GetThreadList ()
+{
+ return m_thread_list;
+}
+
+const ThreadList &
+Process::GetThreadList () const
+{
+ return m_thread_list;
+}
+
+
+bool
+Process::StartPrivateStateThread ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS);
+
+ if (log)
+ log->Printf ("Process::%s ( )", __FUNCTION__);
+
+ // Create a thread that watches our internal state and controls which
+ // events make it to clients (into the DCProcess event queue).
+ m_private_state_thread = Host::ThreadCreate ("<lldb.process.internal-state>", Process::PrivateStateThread, this, NULL);
+ return m_private_state_thread != LLDB_INVALID_HOST_THREAD;
+}
+
+void
+Process::PausePrivateStateThread ()
+{
+ ControlPrivateStateThread (eBroadcastInternalStateControlPause);
+}
+
+void
+Process::ResumePrivateStateThread ()
+{
+ ControlPrivateStateThread (eBroadcastInternalStateControlResume);
+}
+
+void
+Process::StopPrivateStateThread ()
+{
+ ControlPrivateStateThread (eBroadcastInternalStateControlStop);
+}
+
+void
+Process::ControlPrivateStateThread (uint32_t signal)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS);
+
+ assert (signal == eBroadcastInternalStateControlStop ||
+ signal == eBroadcastInternalStateControlPause ||
+ signal == eBroadcastInternalStateControlResume);
+
+ if (log)
+ log->Printf ("Process::%s ( ) - signal: %d", __FUNCTION__, signal);
+
+ // Signal the private state thread
+ if (m_private_state_thread != LLDB_INVALID_HOST_THREAD)
+ {
+ TimeValue timeout_time;
+ bool timed_out;
+
+ m_private_state_control_broadcaster.BroadcastEvent (signal, NULL);
+
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(2);
+ 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)
+ Host::ThreadCancel (m_private_state_thread, NULL);
+
+ thread_result_t result = NULL;
+ Host::ThreadJoin (m_private_state_thread, &result, NULL);
+ }
+ }
+}
+
+void
+Process::HandlePrivateEvent (EventSP &event_sp)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ const StateType internal_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+ // See if we should broadcast this state to external clients?
+ const bool should_broadcast = ShouldBroadcastEvent (event_sp.get());
+ if (log)
+ log->Printf ("Process::%s (arg = %p, pid = %i) got event '%s' broadcast = %s", __FUNCTION__, this, GetID(), StateAsCString(internal_state), should_broadcast ? "yes" : "no");
+
+ if (should_broadcast)
+ {
+ if (log)
+ {
+ log->Printf ("\tChanging public state from: %s to %s", StateAsCString(GetState ()), StateAsCString (internal_state));
+ }
+ Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get());
+ BroadcastEvent (event_sp);
+ }
+ else
+ {
+ if (log)
+ {
+ log->Printf ("\tNot changing public state with event: %s", StateAsCString (internal_state));
+ }
+ }
+}
+
+void *
+Process::PrivateStateThread (void *arg)
+{
+ Process *proc = static_cast<Process*> (arg);
+ void *result = proc->RunPrivateStateThread ();
+ proc->m_private_state_thread = LLDB_INVALID_HOST_THREAD;
+ return result;
+}
+
+void *
+Process::RunPrivateStateThread ()
+{
+ bool control_only = false;
+ 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 = %i) 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))
+ {
+ switch (event_sp->GetType())
+ {
+ case eBroadcastInternalStateControlStop:
+ exit_now = true;
+ continue; // Go to next loop iteration so we exit without
+ 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);
+ }
+
+
+ const StateType internal_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ if (internal_state != eStateInvalid)
+ {
+ HandlePrivateEvent (event_sp);
+ }
+
+ if (internal_state == eStateInvalid || internal_state == eStateExited)
+ break;
+ }
+
+ if (log)
+ log->Printf ("Process::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, this, GetID());
+
+ return NULL;
+}
+
+addr_t
+Process::GetSectionLoadAddress (const Section *section) const
+{
+ // TODO: add support for the same section having multiple load addresses
+ addr_t section_load_addr = LLDB_INVALID_ADDRESS;
+ if (m_section_load_info.GetFirstKeyForValue (section, section_load_addr))
+ return section_load_addr;
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+Process::SectionLoaded (const Section *section, addr_t load_addr)
+{
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_SHLIB | LIBLLDB_LOG_VERBOSE);
+
+ if (log)
+ log->Printf ("Process::%s (section = %p (%s.%s), load_addr = 0x%16.16llx)",
+ __FUNCTION__,
+ section,
+ section->GetModule()->GetFileSpec().GetFilename().AsCString(),
+ section->GetName().AsCString(),
+ load_addr);
+
+
+ const Section *existing_section = NULL;
+ Mutex::Locker locker(m_section_load_info.GetMutex());
+
+ if (m_section_load_info.GetValueForKeyNoLock (load_addr, existing_section))
+ {
+ if (existing_section == section)
+ return false; // No change
+ }
+ m_section_load_info.SetValueForKeyNoLock (load_addr, section);
+ return true; // Changed
+}
+
+size_t
+Process::SectionUnloaded (const Section *section)
+{
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_SHLIB | LIBLLDB_LOG_VERBOSE);
+
+ if (log)
+ log->Printf ("Process::%s (section = %p (%s.%s))",
+ __FUNCTION__,
+ section,
+ section->GetModule()->GetFileSpec().GetFilename().AsCString(),
+ section->GetName().AsCString());
+
+ Mutex::Locker locker(m_section_load_info.GetMutex());
+
+ size_t unload_count = 0;
+ addr_t section_load_addr;
+ while (m_section_load_info.GetFirstKeyForValueNoLock (section, section_load_addr))
+ {
+ unload_count += m_section_load_info.EraseNoLock (section_load_addr);
+ }
+ return unload_count;
+}
+
+bool
+Process::SectionUnloaded (const Section *section, addr_t load_addr)
+{
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_SHLIB | LIBLLDB_LOG_VERBOSE);
+
+ if (log)
+ log->Printf ("Process::%s (section = %p (%s.%s), load_addr = 0x%16.16llx)",
+ __FUNCTION__,
+ section,
+ section->GetModule()->GetFileSpec().GetFilename().AsCString(),
+ section->GetName().AsCString(),
+ load_addr);
+
+ return m_section_load_info.Erase (load_addr) == 1;
+}
+
+
+bool
+Process::ResolveLoadAddress (addr_t load_addr, Address &so_addr) const
+{
+ addr_t section_load_addr = LLDB_INVALID_ADDRESS;
+ const Section *section = NULL;
+
+ // First find the top level section that this load address exists in
+ if (m_section_load_info.LowerBound (load_addr, section_load_addr, section, true))
+ {
+ addr_t offset = load_addr - section_load_addr;
+ if (offset < section->GetByteSize())
+ {
+ // We have found the top level section, now we need to find the
+ // deepest child section.
+ return section->ResolveContainedAddress (offset, so_addr);
+ }
+ }
+ so_addr.Clear();
+ return false;
+}
+
+//------------------------------------------------------------------
+// Process Event Data
+//------------------------------------------------------------------
+
+Process::ProcessEventData::ProcessEventData () :
+ EventData (),
+ m_process_sp (),
+ m_state (eStateInvalid),
+ m_update_state (false),
+ m_restarted (false)
+{
+}
+
+Process::ProcessEventData::ProcessEventData (const ProcessSP &process_sp, StateType state) :
+ EventData (),
+ m_process_sp (process_sp),
+ m_state (state),
+ m_update_state (false),
+ m_restarted (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 ();
+}
+
+const ProcessSP &
+Process::ProcessEventData::GetProcessSP () const
+{
+ return m_process_sp;
+}
+
+StateType
+Process::ProcessEventData::GetState () const
+{
+ return m_state;
+}
+
+bool
+Process::ProcessEventData::GetRestarted () const
+{
+ return m_restarted;
+}
+
+void
+Process::ProcessEventData::SetRestarted (bool new_value)
+{
+ m_restarted = new_value;
+}
+
+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 once when it gets pulled off of
+ // the public event queue. m_update_state is used to distinguish these
+ // two cases; it is false when we're just pulling it off for private handling,
+ // and we don't want to do the breakpoint command handling then.
+
+ if (!m_update_state)
+ return;
+
+ m_process_sp->SetPublicState (m_state);
+
+ // If we're stopped and haven't restarted, then do the breakpoint commands here:
+ if (m_state == eStateStopped && ! m_restarted)
+ {
+ int num_threads = m_process_sp->GetThreadList().GetSize();
+ int idx;
+
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ lldb::ThreadSP thread_sp = m_process_sp->GetThreadList().GetThreadAtIndex(idx);
+
+ Thread::StopInfo stop_info;
+ if (thread_sp->GetStopInfo(&stop_info))
+ {
+ StopReason reason = stop_info.GetStopReason();
+ if (reason == eStopReasonBreakpoint)
+ {
+ BreakpointSiteSP bp_site_sp;
+ // Look up the breakpoint site in the stop info, but the breakpoint
+ // might be a temporary one that's been deleted between the time we
+ // hit the breakpoint and now, if so there's nothing to do.
+
+ bp_site_sp = m_process_sp->GetBreakpointSiteList().FindByID (stop_info.GetBreakpointSiteID());
+ if (bp_site_sp)
+ {
+ size_t num_owners = bp_site_sp->GetNumberOfOwners();
+ for (size_t j = 0; j < num_owners; j++)
+ {
+ lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
+ StoppointCallbackContext context (event_ptr,
+ m_process_sp.get(),
+ thread_sp.get(),
+ thread_sp->GetStackFrameAtIndex(0).get(),
+ false);
+ bp_loc_sp->InvokeCallback (&context);
+ }
+ }
+ else
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+
+ if (log)
+ log->Printf ("Process::%s could not find breakpoint site id: %d...", __FUNCTION__, stop_info.GetBreakpointSiteID());
+ }
+
+ }
+ }
+ }
+ if (m_process_sp->GetPrivateState() == eStateRunning)
+ SetRestarted(true);
+ }
+}
+
+void
+Process::ProcessEventData::Dump (Stream *s) const
+{
+ if (m_process_sp)
+ s->Printf(" process = %p (pid = %u), ", 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);
+}
+
+bool
+Process::ProcessEventData::SetUpdateStateOnRemoval (Event *event_ptr)
+{
+ ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
+ if (data)
+ {
+ data->SetUpdateStateOnRemoval();
+ return true;
+ }
+ return false;
+}
+
+void
+Process::ProcessEventData::SetUpdateStateOnRemoval()
+{
+ m_update_state = true;
+}
+
+Target *
+Process::CalculateTarget ()
+{
+ return &m_target;
+}
+
+Process *
+Process::CalculateProcess ()
+{
+ return this;
+}
+
+Thread *
+Process::CalculateThread ()
+{
+ return NULL;
+}
+
+StackFrame *
+Process::CalculateStackFrame ()
+{
+ return NULL;
+}
+
+void
+Process::Calculate (ExecutionContext &exe_ctx)
+{
+ exe_ctx.target = &m_target;
+ exe_ctx.process = this;
+ exe_ctx.thread = NULL;
+ exe_ctx.frame = NULL;
+}
+
+lldb::ProcessSP
+Process::GetSP ()
+{
+ return GetTarget().GetProcessSP();
+}
+
+ObjCObjectPrinter &
+Process::GetObjCObjectPrinter()
+{
+ return m_objc_object_printer;
+}
+
diff --git a/lldb/source/Target/RegisterContext.cpp b/lldb/source/Target/RegisterContext.cpp
new file mode 100644
index 00000000000..b1838ba477a
--- /dev/null
+++ b/lldb/source/Target/RegisterContext.cpp
@@ -0,0 +1,238 @@
+//===-- 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/Scalar.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContext constructor
+//----------------------------------------------------------------------
+RegisterContext::RegisterContext (Thread &thread, StackFrame *frame) :
+ m_thread (thread),
+ m_frame (frame)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContext::~RegisterContext()
+{
+}
+
+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)
+ {
+ if (m_frame)
+ m_frame->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)
+ {
+ Scalar value;
+ if (ReadRegisterValue (reg, value))
+ return value.GetRawBits64(fail_value);
+ }
+ return fail_value;
+}
+
+bool
+RegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval)
+{
+ if (reg == LLDB_INVALID_REGNUM)
+ return false;
+ Scalar value(uval);
+ return WriteRegisterValue (reg, value);
+}
+
+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;
+}
+
+Target *
+RegisterContext::CalculateTarget ()
+{
+ return m_thread.CalculateTarget();
+}
+
+
+Process *
+RegisterContext::CalculateProcess ()
+{
+ return m_thread.CalculateProcess ();
+}
+
+Thread *
+RegisterContext::CalculateThread ()
+{
+ return &m_thread;
+}
+
+StackFrame *
+RegisterContext::CalculateStackFrame ()
+{
+ return m_frame;
+}
+
+void
+RegisterContext::Calculate (ExecutionContext &exe_ctx)
+{
+ if (m_frame)
+ m_frame->Calculate (exe_ctx);
+ else
+ m_thread.Calculate (exe_ctx);
+}
+
+
+
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
new file mode 100644
index 00000000000..cb832951661
--- /dev/null
+++ b/lldb/source/Target/StackFrame.cpp
@@ -0,0 +1,393 @@
+//===-- 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/Target/StackFrame.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Value.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"
+
+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_PC_SO_ADDR (uint32_t(eSymbolContextEverything + 1))
+#define RESOLVED_FRAME_ID (RESOLVED_PC_SO_ADDR << 1)
+#define GOT_FRAME_BASE (RESOLVED_FRAME_ID << 1)
+#define FRAME_IS_OBSOLETE (GOT_FRAME_BASE << 1)
+#define RESOLVED_VARIABLES (FRAME_IS_OBSOLETE << 1)
+
+StackFrame::StackFrame (lldb::user_id_t frame_idx, Thread &thread, lldb::addr_t cfa, lldb::addr_t pc, const SymbolContext *sc_ptr) :
+ UserID (frame_idx),
+ m_thread (thread),
+ m_reg_context_sp(),
+ m_id(cfa),
+ m_pc(NULL, pc),
+ m_sc(),
+ m_flags(),
+ m_frame_base(),
+ m_frame_base_error(),
+ m_variable_list_sp (),
+ m_value_object_list ()
+{
+ if (sc_ptr != NULL)
+ m_sc = *sc_ptr;
+}
+
+StackFrame::StackFrame (lldb::user_id_t frame_idx, Thread &thread, RegisterContextSP &reg_context_sp, lldb::addr_t cfa, lldb::addr_t pc, const SymbolContext *sc_ptr) :
+ UserID (frame_idx),
+ m_thread (thread),
+ m_reg_context_sp(reg_context_sp),
+ m_id(cfa),
+ m_pc(NULL, pc),
+ m_sc(),
+ m_flags(),
+ m_frame_base(),
+ m_frame_base_error(),
+ m_variable_list_sp (),
+ m_value_object_list ()
+{
+ if (sc_ptr != NULL)
+ m_sc = *sc_ptr;
+}
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StackFrame::~StackFrame()
+{
+}
+
+StackID&
+StackFrame::GetStackID()
+{
+ // Make sure we have resolved our stack ID's address range before we give
+ // it out to any external clients
+ if (m_id.GetStartAddress().IsValid() == 0 && m_flags.IsClear(RESOLVED_FRAME_ID))
+ {
+ m_flags.Set (RESOLVED_FRAME_ID);
+
+ // 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_PC_SO_ADDR))
+ GetPC();
+
+ const uint32_t resolve_scope = eSymbolContextModule |
+ eSymbolContextCompUnit |
+ eSymbolContextFunction;
+
+ if (m_sc.module_sp)
+ {
+ if (m_sc.module_sp->ResolveSymbolContextForAddress (GetPC(), resolve_scope, m_sc) & eSymbolContextFunction)
+ {
+ assert (m_sc.function);
+ m_id.SetStartAddress(m_sc.function->GetAddressRange().GetBaseAddress());
+ }
+ else if (m_sc.module_sp->ResolveSymbolContextForAddress (GetPC(), resolve_scope, m_sc) & eSymbolContextSymbol)
+ {
+ assert (m_sc.symbol);
+ AddressRange *symbol_range_ptr = m_sc.symbol->GetAddressRangePtr();
+ if (symbol_range_ptr)
+ m_id.SetStartAddress(symbol_range_ptr->GetBaseAddress());
+ }
+ }
+// else if (m_sc.target != NULL)
+// {
+// if (m_sc.target->GetImages().ResolveSymbolContextForAddress (GetPC(), resolve_scope, m_sc) & eSymbolContextFunction)
+// {
+// assert (m_sc.function);
+// m_id.GetAddressRange() = m_sc.function->GetAddressRange();
+// }
+// else if (m_sc.target->GetImages().ResolveSymbolContextForAddress (GetPC(), resolve_scope, m_sc) & eSymbolContextSymbol)
+// {
+// assert (m_sc.symbol);
+// AddressRange *symbol_range_ptr = m_sc.symbol->GetAddressRange();
+// if (symbol_range_ptr)
+// m_id.GetAddressRange() = *symbol_range_ptr;
+// }
+// }
+ }
+ return m_id;
+}
+
+Address&
+StackFrame::GetPC()
+{
+ if (m_flags.IsClear(RESOLVED_PC_SO_ADDR) && !m_pc.IsSectionOffset())
+ {
+ m_flags.Set (RESOLVED_PC_SO_ADDR);
+
+ // Resolve the PC into a temporary address because if ResolveLoadAddress
+ // fails to resolve the address, it will clear the address object...
+ Address resolved_pc;
+ if (m_thread.GetProcess().ResolveLoadAddress(m_pc.GetOffset(), resolved_pc))
+ {
+ m_pc = resolved_pc;
+ const Section *section = m_pc.GetSection();
+ if (section)
+ {
+ Module *module = section->GetModule();
+ if (module)
+ {
+ m_sc.module_sp = module->GetSP();
+ if (m_sc.module_sp)
+ m_flags.Set(eSymbolContextModule);
+ }
+ }
+ }
+ }
+ return m_pc;
+}
+
+void
+StackFrame::ChangePC (addr_t pc)
+{
+ m_pc.SetOffset(pc);
+ m_pc.SetSection(NULL);
+ m_sc.Clear();
+ m_flags.SetAllFlagBits(0);
+ m_thread.ClearStackFrames ();
+}
+
+const char *
+StackFrame::Disassemble ()
+{
+ if (m_disassembly.GetSize() == 0)
+ {
+ ExecutionContext exe_ctx;
+ Calculate(exe_ctx);
+ Disassembler::Disassemble (m_thread.GetProcess().GetTarget().GetArchitecture(),
+ exe_ctx,
+ 0,
+ m_disassembly);
+ if (m_disassembly.GetSize() == 0)
+ return NULL;
+ }
+ return m_disassembly.GetData();
+}
+
+//----------------------------------------------------------------------
+// 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.GetAllFlagBits() & resolve_scope) != resolve_scope)
+ {
+ // 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_PC_SO_ADDR))
+ GetPC();
+
+ // 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(GetPC());
+ if (GetID() > 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.
+ if ((m_sc.comp_unit == NULL && (resolve_scope & eSymbolContextCompUnit ) && m_flags.IsClear(eSymbolContextCompUnit )) ||
+ (m_sc.function == NULL && (resolve_scope & eSymbolContextFunction ) && m_flags.IsClear(eSymbolContextFunction )) ||
+ (m_sc.block == NULL && (resolve_scope & eSymbolContextBlock ) && m_flags.IsClear(eSymbolContextBlock )) ||
+ (m_sc.symbol == NULL && (resolve_scope & eSymbolContextSymbol ) && m_flags.IsClear(eSymbolContextSymbol )) ||
+ (!m_sc.line_entry.IsValid() && (resolve_scope & eSymbolContextLineEntry) && m_flags.IsClear(eSymbolContextLineEntry )))
+ {
+ // 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
+ const uint32_t resolved = m_sc.module_sp->ResolveSymbolContextForAddress (lookup_addr, resolve_scope, sc);
+ if (resolved & eSymbolContextCompUnit) m_sc.comp_unit = sc.comp_unit;
+ if (resolved & eSymbolContextFunction) m_sc.function = sc.function;
+ if (resolved & eSymbolContextBlock) m_sc.block = sc.block;
+ if (resolved & eSymbolContextSymbol) m_sc.symbol = sc.symbol;
+ if (resolved & eSymbolContextLineEntry) m_sc.line_entry = sc.line_entry;
+ }
+ }
+ 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.
+ m_thread.GetProcess().GetTarget().GetImages().ResolveSymbolContextForAddress (lookup_addr, resolve_scope, m_sc);
+ }
+
+ // If the target was requested add that:
+ if (m_sc.target_sp.get() == NULL)
+ m_sc.target_sp = CalculateProcess()->GetTarget().GetSP();
+
+ // 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.
+ m_flags.Set(resolve_scope);
+ }
+
+ // Return the symbol context with everything that was possible to resolve
+ // resolved.
+ return m_sc;
+}
+
+
+VariableList *
+StackFrame::GetVariableList ()
+{
+ if (m_flags.IsClear(RESOLVED_VARIABLES))
+ {
+ m_flags.Set(RESOLVED_VARIABLES);
+
+ GetSymbolContext(eSymbolContextFunction);
+ if (m_sc.function)
+ {
+ bool get_child_variables = true;
+ bool can_create = true;
+ m_variable_list_sp = m_sc.function->GetBlocks(can_create).GetVariableList (Block::RootID, get_child_variables, can_create);
+ }
+ }
+ return m_variable_list_sp.get();
+}
+
+
+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 (&m_thread.GetProcess(), &m_thread, this);
+ Value expr_value;
+ if (m_sc.function->GetFrameBaseExpression().Evaluate(&exe_ctx, NULL, NULL, expr_value, &m_frame_base_error) < 0)
+ {
+ // 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, NULL);
+ }
+ }
+ 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();
+}
+
+RegisterContext *
+StackFrame::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL)
+ m_reg_context_sp.reset (m_thread.CreateRegisterContextForFrame (this));
+ return m_reg_context_sp.get();
+}
+
+bool
+StackFrame::HasDebugInformation ()
+{
+ GetSymbolContext(eSymbolContextLineEntry);
+ return m_sc.line_entry.IsValid();
+}
+
+ValueObjectList &
+StackFrame::GetValueObjectList()
+{
+ return m_value_object_list;
+}
+
+
+Target *
+StackFrame::CalculateTarget ()
+{
+ return m_thread.CalculateTarget();
+}
+
+Process *
+StackFrame::CalculateProcess ()
+{
+ return m_thread.CalculateProcess();
+}
+
+Thread *
+StackFrame::CalculateThread ()
+{
+ return &m_thread;
+}
+
+StackFrame *
+StackFrame::CalculateStackFrame ()
+{
+ return this;
+}
+
+
+void
+StackFrame::Calculate (ExecutionContext &exe_ctx)
+{
+ m_thread.Calculate (exe_ctx);
+ exe_ctx.frame = this;
+}
+
+void
+StackFrame::Dump (Stream *strm, bool show_frame_index)
+{
+ if (strm == NULL)
+ return;
+
+ if (show_frame_index)
+ strm->Printf("frame #%u: ", GetID());
+ strm->Printf("pc = 0x%0*llx", m_thread.GetProcess().GetAddressByteSize() * 2, GetRegisterContext()->GetPC());
+ SymbolContext sc (GetSymbolContext(eSymbolContextEverything));
+ strm->PutCString(", where = ");
+ sc.DumpStopContext(strm, &m_thread.GetProcess(), GetPC());
+}
+
diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp
new file mode 100644
index 00000000000..8615f714673
--- /dev/null
+++ b/lldb/source/Target/StackFrameList.cpp
@@ -0,0 +1,135 @@
+//===-- StackFrameList.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/StackFrameList.h"
+#include "lldb/Target/StackFrame.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// StackFrameList constructor
+//----------------------------------------------------------------------
+StackFrameList::StackFrameList() :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_frames (),
+ m_current_frame_idx (0)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StackFrameList::~StackFrameList()
+{
+}
+
+
+uint32_t
+StackFrameList::GetNumFrames() const
+{
+ Mutex::Locker locker (m_mutex);
+ return m_frames.size();
+}
+
+// After we have determined the number of frames, we can set the count here
+// and have the frame info be generated on demand.
+void
+StackFrameList::SetNumFrames(uint32_t count)
+{
+ Mutex::Locker locker (m_mutex);
+ return m_frames.resize(count);
+}
+
+StackFrameSP
+StackFrameList::GetFrameAtIndex (uint32_t idx) const
+{
+ StackFrameSP frame_sp;
+ {
+ Mutex::Locker locker (m_mutex);
+ if (idx < m_frames.size())
+ frame_sp = m_frames[idx];
+ }
+ return frame_sp;
+}
+
+bool
+StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp)
+{
+ Mutex::Locker locker (m_mutex);
+ 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::GetCurrentFrameIndex () const
+{
+ Mutex::Locker locker (m_mutex);
+ return m_current_frame_idx;
+}
+
+
+uint32_t
+StackFrameList::SetCurrentFrame (lldb_private::StackFrame *frame)
+{
+ Mutex::Locker locker (m_mutex);
+ const_iterator pos,
+ begin = m_frames.begin(),
+ end = m_frames.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos->get() == frame)
+ {
+ m_current_frame_idx = std::distance (begin, pos);
+ return m_current_frame_idx;
+ }
+ }
+ m_current_frame_idx = 0;
+ return m_current_frame_idx;
+}
+
+// Mark a stack frame as the current frame using the frame index
+void
+StackFrameList::SetCurrentFrameByIndex (uint32_t idx)
+{
+ Mutex::Locker locker (m_mutex);
+ m_current_frame_idx = idx;
+}
+
+// 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();
+}
+
+void
+StackFrameList::InvalidateFrames (uint32_t start_idx)
+{
+ Mutex::Locker locker (m_mutex);
+ size_t num_frames = m_frames.size();
+ while (start_idx < num_frames)
+ {
+ m_frames[start_idx].reset();
+ ++start_idx;
+ }
+}
diff --git a/lldb/source/Target/StackID.cpp b/lldb/source/Target/StackID.cpp
new file mode 100644
index 00000000000..6f903aed6da
--- /dev/null
+++ b/lldb/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
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// StackID constructor
+//----------------------------------------------------------------------
+StackID::StackID() :
+ m_start_address(),
+ m_cfa()
+{
+}
+
+//----------------------------------------------------------------------
+// StackID constructor with args
+//----------------------------------------------------------------------
+StackID::StackID (const Address& start_address, lldb::addr_t cfa) :
+ m_start_address (start_address),
+ m_cfa (cfa)
+{
+}
+
+StackID::StackID (lldb::addr_t cfa) :
+ m_start_address (),
+ m_cfa (cfa)
+{
+}
+
+//----------------------------------------------------------------------
+// StackID copy constructor
+//----------------------------------------------------------------------
+StackID::StackID(const StackID& rhs) :
+ m_start_address (rhs.m_start_address),
+ m_cfa (rhs.m_cfa)
+{
+}
+
+//----------------------------------------------------------------------
+// StackID assignment operator
+//----------------------------------------------------------------------
+const StackID&
+StackID::operator=(const StackID& rhs)
+{
+ if (this != &rhs)
+ {
+ m_start_address = rhs.m_start_address;
+ m_cfa = rhs.m_cfa;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StackID::~StackID()
+{
+}
+
+
+const Address&
+StackID::GetStartAddress() const
+{
+ return m_start_address;
+}
+
+void
+StackID::SetStartAddress(const Address& start_address)
+{
+ m_start_address = start_address;
+}
+
+lldb::addr_t
+StackID::GetCallFrameAddress() const
+{
+ return m_cfa;
+}
+
+
+bool
+lldb_private::operator== (const StackID& lhs, const StackID& rhs)
+{
+ return lhs.GetCallFrameAddress() == rhs.GetCallFrameAddress() && lhs.GetStartAddress() == rhs.GetStartAddress();
+}
+
+bool
+lldb_private::operator!= (const StackID& lhs, const StackID& rhs)
+{
+ return lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress() || lhs.GetStartAddress() != rhs.GetStartAddress();
+}
+
+bool
+lldb_private::operator< (const StackID& lhs, const StackID& rhs)
+{
+ return lhs.GetCallFrameAddress() < rhs.GetCallFrameAddress();
+}
+
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
new file mode 100644
index 00000000000..48f2ea70fd0
--- /dev/null
+++ b/lldb/source/Target/Target.cpp
@@ -0,0 +1,707 @@
+//===-- 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/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/BreakpointResolverName.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Host.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/Debugger.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Target constructor
+//----------------------------------------------------------------------
+Target::Target() :
+ Broadcaster("Target"),
+ m_images(),
+ m_breakpoint_list (false),
+ m_internal_breakpoint_list (true),
+ m_process_sp(),
+ m_triple(),
+ m_search_filter_sp(),
+ m_image_search_paths (ImageSearchPathsChanged, this),
+ m_scratch_ast_context_ap(NULL)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Target::Target()", this);
+}
+
+//----------------------------------------------------------------------
+// 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)
+{
+ s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ s->PutCString("Target\n");
+ s->IndentMore();
+ m_images.Dump(s);
+ m_breakpoint_list.Dump(s);
+ m_internal_breakpoint_list.Dump(s);
+// if (m_process_sp.get())
+// m_process_sp->Dump(s);
+ s->IndentLess();
+}
+
+void
+Target::DeleteCurrentProcess ()
+{
+ if (m_process_sp.get())
+ {
+ if (m_process_sp->IsAlive())
+ m_process_sp->Destroy();
+ else
+ m_process_sp->Finalize();
+
+ // 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();
+ m_process_sp.reset();
+ }
+}
+
+const lldb::ProcessSP &
+Target::CreateProcess (Listener &listener, const char *plugin_name)
+{
+ DeleteCurrentProcess ();
+ m_process_sp.reset(Process::FindPlugin(*this, plugin_name, listener));
+ return m_process_sp;
+}
+
+const lldb::ProcessSP &
+Target::GetProcessSP () const
+{
+ return m_process_sp;
+}
+
+lldb::TargetSP
+Target::GetSP()
+{
+ return Debugger::GetSharedInstance().GetTargetList().GetTargetSP(this);
+}
+
+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::CreateBreakpoint (const FileSpec *containingModule, const FileSpec &file, uint32_t line_no, bool check_inlines, bool internal)
+{
+ SearchFilterSP filter_sp(GetSearchFilterForModule (containingModule));
+ BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine (NULL, file, line_no, check_inlines));
+ return CreateBreakpoint (filter_sp, resolver_sp, internal);
+}
+
+
+BreakpointSP
+Target::CreateBreakpoint (lldb::addr_t load_addr, bool internal)
+{
+ BreakpointSP bp_sp;
+ Address so_addr;
+ // Attempt to resolve our load address if possible, though it is ok if
+ // it doesn't resolve to section/offset.
+
+ Process *process = GetProcessSP().get();
+ if (process && process->ResolveLoadAddress(load_addr, so_addr))
+ bp_sp = CreateBreakpoint(so_addr, internal);
+ return bp_sp;
+}
+
+BreakpointSP
+Target::CreateBreakpoint (Address &addr, bool internal)
+{
+ TargetSP target_sp = this->GetSP();
+ SearchFilterSP filter_sp(new SearchFilter (target_sp));
+ BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, addr));
+ return CreateBreakpoint (filter_sp, resolver_sp, internal);
+}
+
+BreakpointSP
+Target::CreateBreakpoint (FileSpec *containingModule, const char *func_name, bool internal)
+{
+ SearchFilterSP filter_sp(GetSearchFilterForModule (containingModule));
+ BreakpointResolverSP resolver_sp (new BreakpointResolverName (NULL, func_name));
+ return CreateBreakpoint (filter_sp, resolver_sp, internal);
+}
+
+
+SearchFilterSP
+Target::GetSearchFilterForModule (const FileSpec *containingModule)
+{
+ SearchFilterSP filter_sp;
+ lldb::TargetSP target_sp = this->GetSP();
+ 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 (target_sp, *containingModule));
+ }
+ else
+ {
+ if (m_search_filter_sp.get() == NULL)
+ m_search_filter_sp.reset (new SearchFilter (target_sp));
+ filter_sp = m_search_filter_sp;
+ }
+ return filter_sp;
+}
+
+BreakpointSP
+Target::CreateBreakpoint (FileSpec *containingModule, RegularExpression &func_regex, bool internal)
+{
+ SearchFilterSP filter_sp(GetSearchFilterForModule (containingModule));
+ BreakpointResolverSP resolver_sp(new BreakpointResolverName (NULL, func_regex));
+
+ return CreateBreakpoint (filter_sp, resolver_sp, 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);
+ else
+ m_breakpoint_list.Add (bp_sp);
+
+ 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());
+ }
+
+ // Broadcast the breakpoint creation event.
+ if (!internal && EventTypeHasListeners(eBroadcastBitBreakpointChanged))
+ {
+ BroadcastEvent (eBroadcastBitBreakpointChanged,
+ new Breakpoint::BreakpointEventData (Breakpoint::BreakpointEventData::eBreakpointAdded, bp_sp));
+ }
+
+ bp_sp->ResolveBreakpoint();
+ }
+ return bp_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();
+ if (internal_also)
+ m_internal_breakpoint_list.RemoveAll();
+}
+
+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);
+ else
+ m_breakpoint_list.Remove(break_id);
+ 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;
+}
+
+ModuleSP
+Target::GetExecutableModule ()
+{
+ ModuleSP executable_sp;
+ if (m_images.GetSize() > 0)
+ executable_sp = m_images.GetModuleAtIndex(0);
+ return executable_sp;
+}
+
+void
+Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)
+{
+ m_images.Clear();
+ m_scratch_ast_context_ap.reset();
+
+ if (executable_sp.get())
+ {
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "Target::SetExecutableModule (executable = '%s/%s')",
+ executable_sp->GetFileSpec().GetDirectory().AsCString(),
+ executable_sp->GetFileSpec().GetFilename().AsCString());
+
+ m_images.Append(executable_sp); // The first image is our exectuable file
+
+ ArchSpec exe_arch = executable_sp->GetArchitecture();
+ FileSpecList dependent_files;
+ ObjectFile * executable_objfile = executable_sp->GetObjectFile();
+ if (executable_objfile == NULL)
+ {
+
+ FileSpec bundle_executable(executable_sp->GetFileSpec());
+ if (Host::ResolveExecutableInBundle (&bundle_executable))
+ {
+ ModuleSP bundle_exe_module_sp(GetSharedModule(bundle_executable,
+ exe_arch));
+ SetExecutableModule (bundle_exe_module_sp, get_dependent_files);
+ if (bundle_exe_module_sp->GetObjectFile() != NULL)
+ executable_sp = bundle_exe_module_sp;
+ return;
+ }
+ }
+
+ if (executable_objfile)
+ {
+ executable_objfile->GetDependentModules(dependent_files);
+ for (uint32_t i=0; i<dependent_files.GetSize(); i++)
+ {
+ ModuleSP image_module_sp(GetSharedModule(dependent_files.GetFileSpecPointerAtIndex(i),
+ exe_arch));
+ if (image_module_sp.get())
+ {
+ //image_module_sp->Dump(&s);// REMOVE THIS, DEBUG ONLY
+ ObjectFile *objfile = image_module_sp->GetObjectFile();
+ if (objfile)
+ objfile->GetDependentModules(dependent_files);
+ }
+ }
+ }
+
+ // Now see if we know the target triple, and if so, create our scratch AST context:
+ ConstString target_triple;
+ if (GetTargetTriple(target_triple))
+ {
+ m_scratch_ast_context_ap.reset (new ClangASTContext(target_triple.GetCString()));
+ }
+ }
+}
+
+
+ModuleList&
+Target::GetImages ()
+{
+ return m_images;
+}
+
+ArchSpec
+Target::GetArchitecture () const
+{
+ ArchSpec arch;
+ if (m_images.GetSize() > 0)
+ {
+ Module *exe_module = m_images.GetModulePointerAtIndex(0);
+ if (exe_module)
+ arch = exe_module->GetArchitecture();
+ }
+ return arch;
+}
+
+
+
+bool
+Target::GetTargetTriple(ConstString &triple)
+{
+ triple.Clear();
+
+ if (m_triple)
+ {
+ triple = m_triple;
+ }
+ else
+ {
+ Module *exe_module = GetExecutableModule().get();
+ if (exe_module)
+ {
+ ObjectFile *objfile = exe_module->GetObjectFile();
+ if (objfile)
+ {
+ objfile->GetTargetTriple(m_triple);
+ triple = m_triple;
+ }
+ }
+ }
+ return !triple.IsEmpty();
+}
+
+void
+Target::ModuleAdded (ModuleSP &module_sp)
+{
+ // A module is being added to this target for the first time
+ ModuleList module_list;
+ module_list.Append(module_sp);
+ ModulesDidLoad (module_list);
+}
+
+void
+Target::ModuleUpdated (ModuleSP &old_module_sp, ModuleSP &new_module_sp)
+{
+ // A module is being added to this target for the first time
+ ModuleList module_list;
+ module_list.Append (old_module_sp);
+ ModulesDidUnload (module_list);
+ module_list.Clear ();
+ module_list.Append (new_module_sp);
+ ModulesDidLoad (module_list);
+}
+
+void
+Target::ModulesDidLoad (ModuleList &module_list)
+{
+ m_breakpoint_list.UpdateBreakpoints (module_list, true);
+ // TODO: make event data that packages up the module_list
+ BroadcastEvent (eBroadcastBitModulesLoaded, NULL);
+}
+
+void
+Target::ModulesDidUnload (ModuleList &module_list)
+{
+ m_breakpoint_list.UpdateBreakpoints (module_list, false);
+ // TODO: make event data that packages up the module_list
+ BroadcastEvent (eBroadcastBitModulesUnloaded, NULL);
+}
+
+size_t
+Target::ReadMemory
+(
+ lldb::AddressType addr_type,
+ lldb::addr_t addr,
+ void *dst,
+ size_t dst_len,
+ Error &error,
+ ObjectFile* objfile
+)
+{
+ size_t bytes_read = 0;
+ error.Clear();
+ switch (addr_type)
+ {
+ case eAddressTypeFile:
+ if (objfile)
+ {
+ if (m_process_sp.get())
+ {
+ // If we have an execution context with a process, lets try and
+ // resolve the file address in "objfile" and read it from the
+ // process
+ Address so_addr(addr, objfile->GetSectionList());
+ lldb::addr_t load_addr = so_addr.GetLoadAddress(m_process_sp.get());
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (objfile->GetFileSpec())
+ error.SetErrorStringWithFormat("0x%llx can't be resolved, %s in not currently loaded.\n", addr, objfile->GetFileSpec().GetFilename().AsCString());
+ else
+ error.SetErrorStringWithFormat("0x%llx can't be resolved.\n", addr, objfile->GetFileSpec().GetFilename().AsCString());
+ }
+ 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%llx failed.\n", load_addr);
+ else
+ error.SetErrorStringWithFormat("Only %zu of %zu bytes were read from memory at 0x%llx.\n", bytes_read, dst_len, load_addr);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Try and read the file based address from the object file's
+ // section data.
+ }
+ }
+ break;
+
+ case eAddressTypeLoad:
+ if (m_process_sp.get())
+ {
+ bytes_read = m_process_sp->ReadMemory(addr, dst, dst_len, error);
+ if (bytes_read != dst_len)
+ {
+ if (error.Success())
+ {
+ if (bytes_read == 0)
+ error.SetErrorStringWithFormat("Read memory from 0x%llx failed.\n", addr);
+ else
+ error.SetErrorStringWithFormat("Only %zu of %zu bytes were read from memory at 0x%llx.\n", bytes_read, dst_len, addr);
+ }
+ }
+ }
+ else
+ error.SetErrorStringWithFormat("Need valid process to read load address.\n");
+ break;
+
+ case eAddressTypeHost:
+ // The address is an address in this process, so just copy it
+ ::memcpy (dst, (uint8_t*)NULL + addr, dst_len);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("Unsupported lldb::AddressType value (%i).\n", addr_type);
+ break;
+ }
+ return bytes_read;
+}
+
+
+ModuleSP
+Target::GetSharedModule
+(
+ const FileSpec& file_spec,
+ const ArchSpec& arch,
+ const UUID *uuid_ptr,
+ const ConstString *object_name,
+ off_t object_offset,
+ Error *error_ptr
+)
+{
+ // Don't pass in the UUID so we can tell if we have a stale value in our list
+ ModuleSP old_module_sp; // This will get filled in if we have a new version of the library
+ bool did_create_module = false;
+ ModuleSP module_sp;
+
+ // If there are image search path entries, try to use them first to acquire a suitable image.
+
+ Error error;
+
+ if (m_image_search_paths.GetSize())
+ {
+ FileSpec transformed_spec;
+ if (m_image_search_paths.RemapPath (file_spec.GetDirectory(), transformed_spec.GetDirectory()))
+ {
+ transformed_spec.GetFilename() = file_spec.GetFilename();
+ error = ModuleList::GetSharedModule (transformed_spec, arch, uuid_ptr, object_name, object_offset, module_sp, &old_module_sp, &did_create_module);
+ }
+ }
+
+ // If a module hasn't been found yet, use the unmodified path.
+
+ if (!module_sp)
+ {
+ error = (ModuleList::GetSharedModule (file_spec, arch, uuid_ptr, object_name, object_offset, module_sp, &old_module_sp, &did_create_module));
+ }
+
+ if (module_sp)
+ {
+ m_images.Append (module_sp);
+ if (did_create_module)
+ {
+ if (old_module_sp && m_images.GetIndexForModule (old_module_sp.get()) != LLDB_INVALID_INDEX32)
+ ModuleUpdated(old_module_sp, module_sp);
+ else
+ ModuleAdded(module_sp);
+ }
+ }
+ if (error_ptr)
+ *error_ptr = error;
+ return module_sp;
+}
+
+
+Target *
+Target::CalculateTarget ()
+{
+ return this;
+}
+
+Process *
+Target::CalculateProcess ()
+{
+ return NULL;
+}
+
+Thread *
+Target::CalculateThread ()
+{
+ return NULL;
+}
+
+StackFrame *
+Target::CalculateStackFrame ()
+{
+ return NULL;
+}
+
+void
+Target::Calculate (ExecutionContext &exe_ctx)
+{
+ exe_ctx.target = this;
+ exe_ctx.process = NULL; // Do NOT fill in process...
+ exe_ctx.thread = NULL;
+ exe_ctx.frame = NULL;
+}
+
+PathMappingList &
+Target::GetImageSearchPathList ()
+{
+ return m_image_search_paths;
+}
+
+void
+Target::ImageSearchPathsChanged
+(
+ const PathMappingList &path_list,
+ void *baton
+)
+{
+ Target *target = (Target *)baton;
+ if (target->m_images.GetSize() > 1)
+ {
+ ModuleSP exe_module_sp (target->GetExecutableModule());
+ if (exe_module_sp)
+ {
+ target->m_images.Clear();
+ target->SetExecutableModule (exe_module_sp, true);
+ }
+ }
+}
+
+ClangASTContext *
+Target::GetScratchClangASTContext()
+{
+ return m_scratch_ast_context_ap.get();
+}
diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp
new file mode 100644
index 00000000000..d92940003d6
--- /dev/null
+++ b/lldb/source/Target/TargetList.cpp
@@ -0,0 +1,342 @@
+//===-- TargetList.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/Broadcaster.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/TargetList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//----------------------------------------------------------------------
+// TargetList constructor
+//----------------------------------------------------------------------
+TargetList::TargetList() :
+ Broadcaster("TargetList"),
+ m_target_list(),
+ m_target_list_mutex (Mutex::eMutexTypeRecursive),
+ m_current_target_idx (0)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+TargetList::~TargetList()
+{
+ Mutex::Locker locker(m_target_list_mutex);
+ m_target_list.clear();
+}
+
+Error
+TargetList::CreateTarget
+(
+ const FileSpec& file,
+ const ArchSpec& arch,
+ const UUID *uuid_ptr,
+ bool get_dependent_files,
+ TargetSP &target_sp
+)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "TargetList::CreateTarget (file = '%s/%s', arch = '%s', uuid = %p)",
+ file.GetDirectory().AsCString(),
+ file.GetFilename().AsCString(),
+ arch.AsCString(),
+ uuid_ptr);
+ ModuleSP exe_module_sp;
+ FileSpec resolved_file(file);
+ if (!Host::ResolveExecutableInBundle (&resolved_file))
+ resolved_file = file;
+
+ Error error = ModuleList::GetSharedModule(resolved_file,
+ arch,
+ uuid_ptr,
+ NULL,
+ 0,
+ exe_module_sp,
+ NULL,
+ NULL);
+ if (exe_module_sp)
+ {
+ target_sp.reset(new Target);
+ target_sp->SetExecutableModule (exe_module_sp, get_dependent_files);
+
+ if (target_sp.get())
+ {
+ Mutex::Locker locker(m_target_list_mutex);
+ m_current_target_idx = m_target_list.size();
+ m_target_list.push_back(target_sp);
+ }
+
+// target_sp.reset(new Target);
+// // Let the target resolve any funky bundle paths before we try and get
+// // the object file...
+// target_sp->SetExecutableModule (exe_module_sp, get_dependent_files);
+// if (exe_module_sp->GetObjectFile() == NULL)
+// {
+// error.SetErrorStringWithFormat("%s%s%s: doesn't contain architecture %s",
+// file.GetDirectory().AsCString(),
+// file.GetDirectory() ? "/" : "",
+// file.GetFilename().AsCString(),
+// arch.AsCString());
+// }
+// else
+// {
+// if (target_sp.get())
+// {
+// error.Clear();
+// Mutex::Locker locker(m_target_list_mutex);
+// m_current_target_idx = m_target_list.size();
+// m_target_list.push_back(target_sp);
+// }
+// }
+ }
+ else
+ {
+ target_sp.reset();
+ }
+
+ 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)
+ {
+ ModuleSP module_sp ((*pos)->GetExecutableModule());
+
+ if (module_sp)
+ {
+ if (FileSpec::Equal (exe_file_spec, module_sp->GetFileSpec(), full_match))
+ {
+ if (exe_arch_ptr)
+ {
+ if (*exe_arch_ptr != module_sp->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->BroadcastEvent (Process::eBroadcastBitInterrupt, NULL);
+ ++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::SetCurrentTarget (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_current_target_idx = std::distance (begin, pos);
+ return m_current_target_idx;
+ }
+ }
+ m_current_target_idx = 0;
+ return m_current_target_idx;
+}
+
+lldb::TargetSP
+TargetList::GetCurrentTarget ()
+{
+ Mutex::Locker locker (m_target_list_mutex);
+ if (m_current_target_idx >= m_target_list.size())
+ m_current_target_idx = 0;
+ return GetTargetAtIndex (m_current_target_idx);
+}
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
new file mode 100644
index 00000000000..2f852cc3eae
--- /dev/null
+++ b/lldb/source/Target/Thread.cpp
@@ -0,0 +1,1121 @@
+//===-- 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-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Target/ThreadPlanContinue.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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Thread::Thread (Process &process, lldb::tid_t tid) :
+ UserID (tid),
+ m_index_id (process.GetNextThreadIndexID ()),
+ m_reg_context_sp (),
+ m_process (process),
+ m_state (eStateUnloaded),
+ m_plan_stack (),
+ m_immediate_plan_stack(),
+ m_completed_plan_stack(),
+ m_state_mutex (Mutex::eMutexTypeRecursive),
+ m_frames (),
+ m_current_frame_idx (0),
+ m_resume_signal (LLDB_INVALID_SIGNAL_NUMBER),
+ m_resume_state (eStateRunning)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Thread::Thread(tid = 0x%4.4x)", this, GetID());
+
+ QueueFundamentalPlan(true);
+}
+
+
+Thread::~Thread()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT);
+ if (log)
+ log->Printf ("%p Thread::~Thread(tid = 0x%4.4x)", this, GetID());
+}
+
+int
+Thread::GetResumeSignal () const
+{
+ return m_resume_signal;
+}
+
+void
+Thread::SetResumeSignal (int signal)
+{
+ m_resume_signal = signal;
+}
+
+StateType
+Thread::GetResumeState () const
+{
+ return m_resume_state;
+}
+
+void
+Thread::SetResumeState (StateType state)
+{
+ m_resume_state = state;
+}
+
+Thread::StopInfo::StopInfo(Thread *thread) :
+ m_reason (eStopReasonInvalid),
+ m_description (),
+ m_thread (thread),
+ m_details ()
+{
+ m_description[0] = '\0';
+}
+
+Thread::StopInfo::~StopInfo()
+{
+}
+
+
+void
+Thread::StopInfo::Clear()
+{
+ m_reason = eStopReasonInvalid;
+ m_completed_plan_sp.reset();
+ m_description[0] = '\0';
+ ::bzero (&m_details, sizeof(m_details));
+}
+
+StopReason
+Thread::StopInfo::GetStopReason() const
+{
+ return m_reason;
+}
+
+const char *
+Thread::StopInfo::GetStopDescription() const
+{
+ if (m_description[0])
+ return m_description;
+ return NULL;
+}
+
+void
+Thread::StopInfo::SetStopDescription(const char *desc)
+{
+ if (desc && desc[0])
+ {
+ ::snprintf (m_description, sizeof(m_description), "%s", desc);
+ }
+ else
+ {
+ m_description[0] = '\0';
+ }
+}
+
+void
+Thread::StopInfo::SetThread (Thread* thread)
+{
+ m_thread = thread;
+}
+
+Thread *
+Thread::StopInfo::GetThread ()
+{
+ return m_thread;
+}
+
+lldb::user_id_t
+Thread::StopInfo::GetBreakpointSiteID() const
+{
+ if (m_reason == eStopReasonBreakpoint)
+ return m_details.breakpoint.bp_site_id;
+ return LLDB_INVALID_BREAK_ID;
+}
+
+void
+Thread::StopInfo::SetStopReasonWithBreakpointSiteID (lldb::user_id_t bp_site_id)
+{
+ m_reason = eStopReasonBreakpoint;
+ m_details.breakpoint.bp_site_id = bp_site_id;
+}
+
+lldb::user_id_t
+Thread::StopInfo::GetWatchpointID() const
+{
+ if (m_reason == eStopReasonWatchpoint)
+ return m_details.watchpoint.watch_id;
+ return LLDB_INVALID_WATCH_ID;
+}
+
+void
+Thread::StopInfo::SetStopReasonWithWatchpointID (lldb::user_id_t watch_id)
+{
+ m_reason = eStopReasonWatchpoint;
+ m_details.watchpoint.watch_id = watch_id;
+}
+
+
+int
+Thread::StopInfo::GetSignal() const
+{
+ if (m_reason == eStopReasonSignal)
+ return m_details.signal.signo;
+ return 0;
+}
+
+lldb::user_id_t
+Thread::StopInfo::GetPlanID() const
+{
+ if (m_reason == eStopReasonPlanComplete)
+ return m_completed_plan_sp->GetID();
+ return LLDB_INVALID_UID;
+}
+
+void
+Thread::StopInfo::SetStopReasonWithSignal (int signo)
+{
+ m_reason = eStopReasonSignal;
+ m_details.signal.signo = signo;
+}
+
+void
+Thread::StopInfo::SetStopReasonToTrace ()
+{
+ m_reason = eStopReasonTrace;
+}
+
+uint32_t
+Thread::StopInfo::GetExceptionType() const
+{
+ if (m_reason == eStopReasonException)
+ return m_details.exception.type;
+ return 0;
+}
+
+size_t
+Thread::StopInfo::GetExceptionDataCount() const
+{
+ if (m_reason == eStopReasonException)
+ return m_details.exception.data_count;
+ return 0;
+}
+
+void
+Thread::StopInfo::SetStopReasonWithException (uint32_t exc_type, size_t exc_data_count)
+{
+ m_reason = eStopReasonException;
+ m_details.exception.type = exc_type;
+ m_details.exception.data_count = exc_data_count;
+}
+
+void
+Thread::StopInfo::SetStopReasonWithPlan (ThreadPlanSP &thread_plan_sp)
+{
+ m_reason = eStopReasonPlanComplete;
+ m_completed_plan_sp = thread_plan_sp;
+}
+
+void
+Thread::StopInfo::SetStopReasonToNone ()
+{
+ Clear();
+ m_reason = eStopReasonNone;
+}
+
+lldb::addr_t
+Thread::StopInfo::GetExceptionDataAtIndex (uint32_t idx) const
+{
+ if (m_reason == eStopReasonException && idx < m_details.exception.data_count)
+ return m_details.exception.data[idx];
+ return 0;
+
+}
+
+
+bool
+Thread::StopInfo::SetExceptionDataAtIndex (uint32_t idx, lldb::addr_t data)
+{
+ if (m_reason == eStopReasonException && idx < m_details.exception.data_count)
+ {
+ m_details.exception.data[idx] = data;
+ return true;
+ }
+ return false;
+}
+
+void
+Thread::StopInfo::Dump (Stream *s) const
+{
+ if (m_description[0])
+ s->Printf("%s", m_description);
+ else
+ {
+ switch (m_reason)
+ {
+ case eStopReasonInvalid:
+ s->PutCString("invalid");
+ break;
+
+ case eStopReasonNone:
+ s->PutCString("none");
+ break;
+
+ case eStopReasonTrace:
+ s->PutCString("trace");
+ break;
+
+ case eStopReasonBreakpoint:
+ {
+ bool no_details = true;
+ s->PutCString ("breakpoint ");
+ if (m_thread)
+ {
+ BreakpointSiteSP bp_site_sp = m_thread->GetProcess().GetBreakpointSiteList().FindByID(m_details.breakpoint.bp_site_id);
+ if (bp_site_sp)
+ {
+ bp_site_sp->GetDescription(s, lldb::eDescriptionLevelBrief);
+ no_details = false;
+ }
+ }
+
+ if (no_details)
+ s->Printf ("site id: %d", m_details.breakpoint.bp_site_id);
+ }
+ break;
+
+ case eStopReasonWatchpoint:
+ s->Printf("watchpoint (site id = %u)", m_details.watchpoint.watch_id);
+ break;
+
+ case eStopReasonSignal:
+ {
+ s->Printf("signal: signo = %i", m_details.signal.signo);
+ const char * signal_name = m_thread->GetProcess().GetUnixSignals().GetSignalAsCString (m_details.signal.signo);
+ if (signal_name)
+ s->Printf(" (%s)", signal_name);
+ }
+ break;
+
+ case eStopReasonException:
+ {
+ s->Printf("exception: type = 0x%8.8x, data_count = %zu", m_details.exception.type, m_details.exception.data_count);
+ uint32_t i;
+ for (i=0; i<m_details.exception.data_count; ++i)
+ {
+ s->Printf(", data[%u] = 0x%8.8llx", i, m_details.exception.data[i]);
+ }
+ }
+ break;
+
+ case eStopReasonPlanComplete:
+ {
+ m_completed_plan_sp->GetDescription (s, lldb::eDescriptionLevelBrief);
+ }
+ break;
+ }
+ }
+}
+
+bool
+Thread::GetStopInfo (Thread::StopInfo *stop_info)
+{
+ stop_info->SetThread(this);
+ ThreadPlanSP completed_plan = GetCompletedPlan();
+ if (completed_plan != NULL)
+ {
+ stop_info->Clear ();
+ stop_info->SetStopReasonWithPlan (completed_plan);
+ return true;
+ }
+ else
+ return GetRawStopReason (stop_info);
+}
+
+bool
+Thread::ThreadStoppedForAReason (void)
+{
+ Thread::StopInfo stop_info;
+ stop_info.SetThread(this);
+ if (GetRawStopReason (&stop_info))
+ {
+ StopReason reason = stop_info.GetStopReason();
+ if (reason == eStopReasonInvalid || reason == eStopReasonNone)
+ return false;
+ else
+ return true;
+ }
+ else
+ return false;
+}
+
+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.
+
+ lldb::addr_t pc = GetRegisterContext()->GetPC();
+ BreakpointSiteSP bp_site_sp = GetProcess().GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp && bp_site_sp->IsEnabled())
+ {
+ // Note, don't assume there's a ThreadPlanStepOverBreakpoint, the target may not require anything
+ // special to step over a breakpoint.
+
+ ThreadPlan *cur_plan = GetCurrentPlan();
+ ThreadPlanStepOverBreakpoint *step_over_bp = dynamic_cast<ThreadPlanStepOverBreakpoint *> (cur_plan);
+ if (step_over_bp == NULL)
+ {
+
+ ThreadPlanSP step_bp_plan_sp (new ThreadPlanStepOverBreakpoint (*this));
+ if (step_bp_plan_sp)
+ {
+ if (GetCurrentPlan()->RunState() != eStateStepping)
+ {
+ ThreadPlanSP continue_plan_sp (new ThreadPlanContinue(*this, false, eVoteNo, eVoteNoOpinion));
+ continue_plan_sp->SetPrivate (true);
+ QueueThreadPlan (continue_plan_sp, false);
+ }
+ step_bp_plan_sp->SetPrivate (true);
+ QueueThreadPlan (step_bp_plan_sp, false);
+ }
+ }
+ }
+ }
+}
+
+bool
+Thread::WillResume (StateType resume_state)
+{
+ // At this point clear the completed plan stack.
+ m_completed_plan_stack.clear();
+ m_discarded_plan_stack.clear();
+
+ // If this thread stopped with a signal, work out what its resume state should
+ // be. Note if the thread resume state is already set, then don't override it,
+ // the user must have asked us to resume with some other signal.
+
+ if (GetResumeSignal() == LLDB_INVALID_SIGNAL_NUMBER)
+ {
+ Thread::StopInfo stop_info;
+ GetRawStopReason(&stop_info);
+
+ StopReason reason = stop_info.GetStopReason();
+ if (reason == eStopReasonSignal)
+ {
+ UnixSignals &signals = GetProcess().GetUnixSignals();
+ int32_t signo = stop_info.GetSignal();
+ if (!signals.GetShouldSuppress(signo))
+ {
+ SetResumeSignal(signo);
+ }
+ }
+ }
+
+ // 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.
+
+ ThreadPlan *plan_ptr = GetCurrentPlan();
+ plan_ptr->WillResume(resume_state, true);
+
+ while ((plan_ptr = GetPreviousPlan(plan_ptr)) != NULL)
+ {
+ plan_ptr->WillResume (resume_state, false);
+ }
+ return true;
+}
+
+void
+Thread::DidResume ()
+{
+ SetResumeSignal (LLDB_INVALID_SIGNAL_NUMBER);
+}
+
+bool
+Thread::ShouldStop (Event* event_ptr)
+{
+ ThreadPlan *current_plan = GetCurrentPlan();
+ bool should_stop = true;
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ {
+ StreamString s;
+ DumpThreadPlans(&s);
+ log->PutCString (s.GetData());
+ }
+
+ if (current_plan->PlanExplainsStop())
+ {
+ while (1)
+ {
+ should_stop = current_plan->ShouldStop(event_ptr);
+ 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;
+ }
+ }
+ }
+ 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())
+ {
+ should_stop = plan_ptr->ShouldStop (event_ptr);
+ break;
+ }
+
+ }
+ }
+
+ return should_stop;
+}
+
+Vote
+Thread::ShouldReportStop (Event* event_ptr)
+{
+ StateType thread_state = GetResumeState ();
+ if (thread_state == eStateSuspended
+ || thread_state == eStateInvalid)
+ return eVoteNoOpinion;
+
+ if (m_completed_plan_stack.size() > 0)
+ {
+ // Don't use GetCompletedPlan here, since that suppresses private plans.
+ return m_completed_plan_stack.back()->ShouldReportStop (event_ptr);
+ }
+ else
+ return GetCurrentPlan()->ShouldReportStop (event_ptr);
+}
+
+Vote
+Thread::ShouldReportRun (Event* event_ptr)
+{
+ StateType thread_state = GetResumeState ();
+ if (thread_state == eStateSuspended
+ || thread_state == eStateInvalid)
+ return eVoteNoOpinion;
+
+ if (m_completed_plan_stack.size() > 0)
+ {
+ // Don't use GetCompletedPlan here, since that suppresses private plans.
+ return m_completed_plan_stack.back()->ShouldReportRun (event_ptr);
+ }
+ else
+ return GetCurrentPlan()->ShouldReportRun (event_ptr);
+}
+
+void
+Thread::PushPlan (ThreadPlanSP &thread_plan_sp)
+{
+ if (thread_plan_sp)
+ {
+ if (thread_plan_sp->IsImmediate())
+ m_immediate_plan_stack.push_back (thread_plan_sp);
+ else
+ 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("Pushing plan: \"%s\" for thread: %d immediate: %s.",
+ s.GetData(),
+ thread_plan_sp->GetThread().GetID(),
+ thread_plan_sp->IsImmediate() ? "true" : "false");
+ }
+ }
+}
+
+void
+Thread::PopPlan ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ if (!m_immediate_plan_stack.empty())
+ {
+ ThreadPlanSP &plan = m_immediate_plan_stack.back();
+ if (log)
+ {
+ log->Printf("Popping plan: \"%s\" for thread: %d immediate: true.", plan->GetName(), plan->GetThread().GetID());
+ }
+ plan->WillPop();
+ m_immediate_plan_stack.pop_back();
+ }
+ else if (m_plan_stack.empty())
+ return;
+ else
+ {
+ ThreadPlanSP &plan = m_plan_stack.back();
+ if (log)
+ {
+ log->Printf("Popping plan: \"%s\" for thread: 0x%x immediate: false.", plan->GetName(), plan->GetThread().GetID());
+ }
+ m_completed_plan_stack.push_back (plan);
+ plan->WillPop();
+ m_plan_stack.pop_back();
+ }
+}
+
+void
+Thread::DiscardPlan ()
+{
+ if (m_plan_stack.size() > 1)
+ {
+ ThreadPlanSP &plan = m_plan_stack.back();
+ m_discarded_plan_stack.push_back (plan);
+ plan->WillPop();
+ m_plan_stack.pop_back();
+ }
+}
+
+ThreadPlan *
+Thread::GetCurrentPlan ()
+{
+ if (!m_immediate_plan_stack.empty())
+ return m_immediate_plan_stack.back().get();
+ else if (m_plan_stack.empty())
+ return NULL;
+ else
+ 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;
+}
+
+bool
+Thread::IsThreadPlanDone (ThreadPlan *plan)
+{
+ ThreadPlanSP empty_plan_sp;
+ 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)
+{
+ ThreadPlanSP empty_plan_sp;
+ 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_immediate_plan_stack.size() > 0)
+ return m_immediate_plan_stack.back().get();
+ else if (m_plan_stack.size() > 0)
+ return m_plan_stack.back().get();
+ else
+ return NULL;
+ }
+
+ stack_size = m_immediate_plan_stack.size();
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ if (current_plan == m_immediate_plan_stack[i].get())
+ return m_immediate_plan_stack[i-1].get();
+ }
+ if (stack_size > 0 && m_immediate_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::DiscardThreadPlans(bool force)
+{
+ // FIXME: It is not always safe to just discard plans. Some, like the step over
+ // breakpoint trap can't be discarded in general (though you can if you plan to
+ // force a return from a function, for instance.
+ // For now I'm just not clearing immediate plans, but I need a way for plans to
+ // say they really need to be kept on, and then a way to override that. Humm...
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ {
+ log->Printf("Discarding thread plans for thread: 0x%x: 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;
+
+ // 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;
+ }
+
+ }
+ // FIXME: What should we do about the immediate plans?
+}
+
+ThreadPlan *
+Thread::QueueFundamentalPlan (bool abort_other_plans)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanBase(*this));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+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.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForStepRange (bool abort_other_plans, StepType type, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp;
+ if (type == eStepTypeInto)
+ thread_plan_sp.reset (new ThreadPlanStepInRange (*this, range, addr_context, stop_other_threads));
+ else
+ thread_plan_sp.reset (new ThreadPlanStepOverRange (*this, range, addr_context, stop_other_threads));
+
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+
+ThreadPlan *
+Thread::QueueThreadPlanForStepOverBreakpointPlan (bool abort_other_plans)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepOverBreakpoint (*this));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForStepOut (bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
+ bool stop_other_threads, Vote stop_vote, Vote run_vote)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForStepThrough (bool abort_other_plans, bool stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp(GetProcess().GetDynamicLoader()->GetStepThroughTrampolinePlan (*this, stop_other_threads));
+ if (thread_plan_sp.get() == NULL)
+ {
+ thread_plan_sp.reset(new ThreadPlanStepThrough (*this, stop_other_threads));
+ if (thread_plan_sp && !thread_plan_sp->ValidatePlan (NULL))
+ return false;
+ }
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForContinue (bool abort_other_plans, bool stop_other_threads, Vote stop_vote, Vote run_vote, bool immediate)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanContinue (*this, stop_other_threads, stop_vote, run_vote, immediate));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForCallFunction (bool abort_other_plans,
+ Address& function,
+ lldb::addr_t arg,
+ bool stop_other_threads,
+ bool discard_on_error)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanCallFunction (*this, function, arg, stop_other_threads, discard_on_error));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForCallFunction (bool abort_other_plans,
+ Address& function,
+ ValueList &args,
+ bool stop_other_threads,
+ bool discard_on_error)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanCallFunction (*this, function, args, stop_other_threads, discard_on_error));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+}
+
+ThreadPlan *
+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.get();
+}
+
+ThreadPlan *
+Thread::QueueThreadPlanForStepUntil (bool abort_other_plans,
+ lldb::addr_t *address_list,
+ size_t num_addresses,
+ bool stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepUntil (*this, address_list, num_addresses, stop_other_threads));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp.get();
+
+}
+
+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();
+ s->Printf ("Plan Stack: %d elements.\n", stack_size);
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ s->Printf ("Element %d: ", i);
+ s->IndentMore();
+ m_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
+ s->IndentLess();
+ s->EOL();
+ }
+
+ stack_size = m_immediate_plan_stack.size();
+ s->Printf ("Immediate Plan Stack: %d elements.\n", stack_size);
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ s->Printf ("Element %d: ", i);
+ s->IndentMore();
+ m_immediate_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
+ s->IndentLess();
+ s->EOL();
+ }
+
+ stack_size = m_completed_plan_stack.size();
+ s->Printf ("Completed Plan Stack: %d elements.\n", stack_size);
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ s->Printf ("Element %d: ", i);
+ s->IndentMore();
+ m_completed_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
+ s->IndentLess();
+ s->EOL();
+ }
+
+ stack_size = m_discarded_plan_stack.size();
+ s->Printf ("Discarded Plan Stack: %d elements.\n", stack_size);
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ s->Printf ("Element %d: ", i);
+ s->IndentMore();
+ m_discarded_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
+ s->IndentLess();
+ s->EOL();
+ }
+
+}
+
+Target *
+Thread::CalculateTarget ()
+{
+ return m_process.CalculateTarget();
+}
+
+Process *
+Thread::CalculateProcess ()
+{
+ return &m_process;
+}
+
+Thread *
+Thread::CalculateThread ()
+{
+ return this;
+}
+
+StackFrame *
+Thread::CalculateStackFrame ()
+{
+ return NULL;
+}
+
+void
+Thread::Calculate (ExecutionContext &exe_ctx)
+{
+ m_process.Calculate (exe_ctx);
+ exe_ctx.thread = this;
+ exe_ctx.frame = NULL;
+}
+
+lldb::StackFrameSP
+Thread::GetCurrentFrame ()
+{
+ return GetStackFrameAtIndex (m_frames.GetCurrentFrameIndex());
+}
+
+uint32_t
+Thread::SetCurrentFrame (lldb_private::StackFrame *frame)
+{
+ return m_frames.SetCurrentFrame(frame);
+}
+
+void
+Thread::SetCurrentFrameByIndex (uint32_t frame_idx)
+{
+ m_frames.SetCurrentFrameByIndex(frame_idx);
+}
+
+void
+Thread::DumpInfo
+(
+ Stream &strm,
+ bool show_stop_reason,
+ bool show_name,
+ bool show_queue,
+ uint32_t frame_idx
+)
+{
+ strm.Printf("thread #%u: tid = 0x%4.4x", GetIndexID(), GetID());
+
+ if (frame_idx != LLDB_INVALID_INDEX32)
+ {
+ StackFrameSP frame_sp(GetStackFrameAtIndex (frame_idx));
+ if (frame_sp)
+ {
+ strm.PutCString(", ");
+ frame_sp->Dump (&strm, false);
+ }
+ }
+
+ if (show_stop_reason)
+ {
+ Thread::StopInfo thread_stop_info;
+ if (GetStopInfo(&thread_stop_info))
+ {
+ if (thread_stop_info.GetStopReason() != eStopReasonNone)
+ {
+ strm.PutCString(", stop reason = ");
+ thread_stop_info.Dump(&strm);
+ }
+ }
+ }
+
+ if (show_name)
+ {
+ const char *name = GetName();
+ if (name && name[0])
+ strm.Printf(", name = %s", name);
+ }
+
+ if (show_queue)
+ {
+ const char *queue = GetQueueName();
+ if (queue && queue[0])
+ strm.Printf(", queue = %s", queue);
+ }
+}
+
+lldb::ThreadSP
+Thread::GetSP ()
+{
+ return m_process.GetThreadList().GetThreadSPForThreadPtr(this);
+}
diff --git a/lldb/source/Target/ThreadList.cpp b/lldb/source/Target/ThreadList.cpp
new file mode 100644
index 00000000000..6bc22712d10
--- /dev/null
+++ b/lldb/source/Target/ThreadList.cpp
@@ -0,0 +1,460 @@
+//===-- 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/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_threads_mutex (Mutex::eMutexTypeRecursive),
+ m_current_tid (LLDB_INVALID_THREAD_ID)
+{
+}
+
+ThreadList::ThreadList (const ThreadList &rhs) :
+ m_process (),
+ m_stop_id (),
+ m_threads (),
+ m_threads_mutex (Mutex::eMutexTypeRecursive),
+ m_current_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_this(m_threads_mutex);
+ Mutex::Locker locker_rhs(rhs.m_threads_mutex);
+ m_process = rhs.m_process;
+ m_stop_id = rhs.m_stop_id;
+ m_threads = rhs.m_threads;
+ m_current_tid = rhs.m_current_tid;
+ }
+ return *this;
+}
+
+
+ThreadList::~ThreadList()
+{
+}
+
+
+uint32_t
+ThreadList::GetStopID () const
+{
+ return m_stop_id;
+}
+
+void
+ThreadList::SetStopID (uint32_t stop_id)
+{
+ m_stop_id = stop_id;
+}
+
+
+void
+ThreadList::AddThread (ThreadSP &thread_sp)
+{
+ Mutex::Locker locker(m_threads_mutex);
+ m_threads.push_back(thread_sp);
+}
+
+uint32_t
+ThreadList::GetSize (bool can_update)
+{
+ Mutex::Locker locker(m_threads_mutex);
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+ return m_threads.size();
+}
+
+ThreadSP
+ThreadList::GetThreadAtIndex (uint32_t idx, bool can_update)
+{
+ Mutex::Locker locker(m_threads_mutex);
+ 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(m_threads_mutex);
+
+ 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::GetThreadSPForThreadPtr (Thread *thread_ptr)
+{
+ ThreadSP thread_sp;
+ if (thread_ptr)
+ {
+ Mutex::Locker locker(m_threads_mutex);
+
+ 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(m_threads_mutex);
+
+ 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)
+{
+ Mutex::Locker locker(m_threads_mutex);
+
+ // Running events should never stop, obviously...
+
+
+ bool should_stop = false;
+ m_process->UpdateThreadListIfNeeded();
+
+ collection::iterator pos, end = m_threads.end();
+
+ // Run through the threads and ask whether we should stop. Don't ask
+ // suspended threads, however, it makes more sense for them to preserve their
+ // state across the times the process runs but they don't get a chance to.
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if ((thread_sp->ThreadStoppedForAReason())
+ && (thread_sp->GetResumeState () != eStateSuspended))
+ {
+ should_stop |= thread_sp->ShouldStop(event_ptr);
+ }
+ }
+ if (should_stop)
+ {
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ thread_sp->WillStop ();
+ }
+ }
+
+ return should_stop;
+}
+
+Vote
+ThreadList::ShouldReportStop (Event *event_ptr)
+{
+ 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.
+ // 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);
+ if (thread_sp->ThreadStoppedForAReason() && (thread_sp->GetResumeState () != eStateSuspended))
+ {
+ switch (thread_sp->ShouldReportStop (event_ptr))
+ {
+ case eVoteNoOpinion:
+ continue;
+ case eVoteYes:
+ result = eVoteYes;
+ break;
+ case eVoteNo:
+ if (result == eVoteNoOpinion)
+ result = eVoteNo;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+Vote
+ThreadList::ShouldReportRun (Event *event_ptr)
+{
+ 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.
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if (thread_sp->GetResumeState () != eStateSuspended)
+
+ switch (thread_sp->ShouldReportRun (event_ptr))
+ {
+ case eVoteNoOpinion:
+ continue;
+ case eVoteYes:
+ if (result == eVoteNoOpinion)
+ result = eVoteYes;
+ break;
+ case eVoteNo:
+ result = eVoteNo;
+ break;
+ }
+ }
+ return result;
+}
+
+void
+ThreadList::Clear()
+{
+ m_stop_id = 0;
+ m_threads.clear();
+ m_current_tid = LLDB_INVALID_THREAD_ID;
+}
+
+void
+ThreadList::RefreshStateAfterStop ()
+{
+ Mutex::Locker locker(m_threads_mutex);
+
+ m_process->UpdateThreadListIfNeeded();
+
+ 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(m_threads_mutex);
+
+ 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.
+ bool success = true;
+
+ Mutex::Locker locker(m_threads_mutex);
+ m_process->UpdateThreadListIfNeeded();
+
+ collection::iterator pos, end = m_threads.end();
+
+ // Give all the threads a last chance to set up their state before we
+ // negotiate who is actually going to get a chance to run...
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ (*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());
+
+ ThreadSP immediate_thread_sp;
+ bool run_only_current_thread = false;
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if (thread_sp->GetCurrentPlan()->IsImmediate())
+ {
+ // We first do all the immediate plans, so if we find one, set
+ // immediate_thread_sp and break out, and we'll pick it up first thing
+ // when we're negotiating which threads get to run.
+ immediate_thread_sp = thread_sp;
+ break;
+ }
+ else if (thread_sp->GetResumeState() != eStateSuspended &&
+ thread_sp->GetCurrentPlan()->StopOthers())
+ {
+ // You can't say "stop others" and also want yourself to be suspended.
+ assert (thread_sp->GetCurrentPlan()->RunState() != eStateSuspended);
+
+ if (thread_sp == GetCurrentThread())
+ {
+ 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);
+ }
+
+ }
+
+ if (immediate_thread_sp)
+ {
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if (thread_sp.get() == immediate_thread_sp.get())
+ thread_sp->WillResume(thread_sp->GetCurrentPlan()->RunState());
+ else
+ thread_sp->WillResume (eStateSuspended);
+ }
+ }
+ else 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);
+ thread_sp->WillResume(thread_sp->GetCurrentPlan()->RunState());
+ }
+ }
+ else
+ {
+ ThreadSP thread_to_run;
+
+ if (run_only_current_thread)
+ {
+ thread_to_run = GetCurrentThread();
+ }
+ 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)
+ thread_sp->WillResume(thread_sp->GetCurrentPlan()->RunState());
+ else
+ thread_sp->WillResume (eStateSuspended);
+ }
+ }
+
+ return success;
+}
+
+void
+ThreadList::DidResume ()
+{
+ 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 ();
+ }
+}
+
+ThreadSP
+ThreadList::GetCurrentThread ()
+{
+ Mutex::Locker locker(m_threads_mutex);
+ return FindThreadByID(m_current_tid);
+}
+
+bool
+ThreadList::SetCurrentThreadByID (lldb::tid_t tid)
+{
+ Mutex::Locker locker(m_threads_mutex);
+ if (FindThreadByID(tid).get())
+ m_current_tid = tid;
+ else
+ m_current_tid = LLDB_INVALID_THREAD_ID;
+
+ return m_current_tid != LLDB_INVALID_THREAD_ID;
+}
+
+bool
+ThreadList::SetCurrentThreadByIndexID (uint32_t index_id)
+{
+ Mutex::Locker locker(m_threads_mutex);
+ ThreadSP thread_sp (FindThreadByIndexID(index_id));
+ if (thread_sp.get())
+ m_current_tid = thread_sp->GetID();
+ else
+ m_current_tid = LLDB_INVALID_THREAD_ID;
+
+ return m_current_tid != LLDB_INVALID_THREAD_ID;
+}
+
diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp
new file mode 100644
index 00000000000..c9005c1f345
--- /dev/null
+++ b/lldb/source/Target/ThreadPlan.cpp
@@ -0,0 +1,185 @@
+//===-- 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/Target/ThreadPlan.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Thread.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlan constructor
+//----------------------------------------------------------------------
+ThreadPlan::ThreadPlan(const char *name, Thread &thread, Vote stop_vote, Vote run_vote) :
+ m_name (name),
+ m_thread (thread),
+ m_plan_complete(false),
+ m_plan_complete_mutex (Mutex::eMutexTypeRecursive),
+ m_plan_private (false),
+ m_stop_vote (stop_vote),
+ m_run_vote (run_vote),
+ m_okay_to_discard (false)
+{
+ SetID (GetNextID());
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ThreadPlan::~ThreadPlan()
+{
+}
+
+const char *
+ThreadPlan::GetName () const
+{
+ return m_name.c_str();
+}
+
+Thread &
+ThreadPlan::GetThread()
+{
+ return m_thread;
+}
+
+
+const Thread &
+ThreadPlan::GetThread() const
+{
+ return m_thread;
+}
+
+bool
+ThreadPlan::IsPlanComplete ()
+{
+ Mutex::Locker (m_plan_complete_mutex);
+ return m_plan_complete;
+}
+
+void
+ThreadPlan::SetPlanComplete ()
+{
+ Mutex::Locker (m_plan_complete_mutex);
+ m_plan_complete = true;
+}
+
+bool
+ThreadPlan::MischiefManaged ()
+{
+ Mutex::Locker (m_plan_complete_mutex);
+ m_plan_complete = true;
+ return true;
+}
+
+Vote
+ThreadPlan::ShouldReportStop (Event *event_ptr)
+{
+ if (m_stop_vote == eVoteNoOpinion)
+ {
+ ThreadPlan *prev_plan = GetPreviousPlan ();
+ if (prev_plan)
+ return prev_plan->ShouldReportStop (event_ptr);
+ }
+ 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();
+}
+
+bool
+ThreadPlan::WillResume (StateType resume_state, bool current_plan)
+{
+ if (current_plan)
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ if (log)
+ log->Printf("About to resume the \"%s\" plan - state: %s - stop others: %d.",
+ m_name.c_str(), StateAsCString(resume_state), StopOthers());
+ }
+ return true;
+}
+
+lldb::user_id_t
+ThreadPlan::GetNextID()
+{
+ static uint32_t g_nextPlanID = 0;
+ return ++g_nextPlanID;
+}
+
+void
+ThreadPlan::DidPush()
+{
+}
+
+void
+ThreadPlan::WillPop()
+{
+}
+
+void
+ThreadPlan::PushPlan (ThreadPlanSP &thread_plan_sp)
+{
+ m_thread.PushPlan (thread_plan_sp);
+}
+
+ThreadPlan *
+ThreadPlan::GetPreviousPlan ()
+{
+ return m_thread.GetPreviousPlan (this);
+}
+
+void
+ThreadPlan::SetPrivate (bool input)
+{
+ m_plan_private = input;
+}
+
+bool
+ThreadPlan::GetPrivate (void)
+{
+ return m_plan_private;
+}
+
+bool
+ThreadPlan::OkayToDiscard()
+{
+ if (!IsMasterPlan())
+ return true;
+ else
+ return m_okay_to_discard;
+}
+
diff --git a/lldb/source/Target/ThreadPlanBase.cpp b/lldb/source/Target/ThreadPlanBase.cpp
new file mode 100644
index 00000000000..283f3bef4c9
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanBase.cpp
@@ -0,0 +1,202 @@
+//===-- 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/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/ThreadPlanContinue.h"
+#include "lldb/Target/ThreadPlanStepOverBreakpoint.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("base plan", thread, eVoteYes, eVoteNoOpinion)
+{
+
+}
+
+ThreadPlanBase::~ThreadPlanBase ()
+{
+
+}
+
+void
+ThreadPlanBase::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ s->Printf ("Base thread plan.");
+}
+
+bool
+ThreadPlanBase::ValidatePlan (Stream *error)
+{
+ return true;
+}
+
+bool
+ThreadPlanBase::PlanExplainsStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanBase::ShouldStop (Event *event_ptr)
+{
+ m_stop_vote = eVoteYes;
+ m_run_vote = eVoteYes;
+
+ Thread::StopInfo stop_info;
+ if (m_thread.GetStopInfo(&stop_info))
+ {
+ StopReason reason = stop_info.GetStopReason();
+ switch (reason)
+ {
+ case eStopReasonInvalid:
+ case eStopReasonNone:
+ {
+ m_run_vote = eVoteNo;
+ m_stop_vote = eVoteNo;
+ return false;
+ }
+ case eStopReasonBreakpoint:
+ {
+ // The base plan checks for breakpoint hits.
+
+ BreakpointSiteSP bp_site_sp;
+ //RegisterContext *reg_ctx = m_thread.GetRegisterContext();
+ //lldb::addr_t pc = reg_ctx->GetPC();
+ bp_site_sp = m_thread.GetProcess().GetBreakpointSiteList().FindByID (stop_info.GetBreakpointSiteID());
+
+ if (bp_site_sp && bp_site_sp->IsEnabled())
+ {
+ // We want to step over the breakpoint and then continue. So push these two plans.
+
+ StoppointCallbackContext hit_context(event_ptr, &m_thread.GetProcess(), &m_thread, m_thread.GetStackFrameAtIndex(0).get());
+ bool should_stop = m_thread.GetProcess().GetBreakpointSiteList().ShouldStop(&hit_context, bp_site_sp->GetID());
+
+ if (!should_stop)
+ {
+ // 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".
+ uint32_t i;
+ bool is_wholly_internal = true;
+
+ for (i = 0; i < bp_site_sp->GetNumberOfOwners(); i++)
+ {
+ if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal())
+ {
+ is_wholly_internal = false;
+ break;
+ }
+ }
+ if (is_wholly_internal)
+ {
+ m_stop_vote = eVoteNo;
+ m_run_vote = eVoteNo;
+ }
+ else
+ {
+ m_stop_vote = eVoteYes;
+ m_run_vote = eVoteYes;
+ }
+
+ }
+ else
+ {
+ // 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.
+ m_thread.DiscardThreadPlans(false);
+ }
+
+ return should_stop;
+ }
+ }
+ 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.
+ m_thread.DiscardThreadPlans(false);
+ return true;
+ case eStopReasonSignal:
+ {
+ // Check the signal handling, and if we are stopping for the signal,
+ // discard the plans and stop.
+ UnixSignals &signals = m_thread.GetProcess().GetUnixSignals();
+ uint32_t signo = stop_info.GetSignal();
+ if (signals.GetShouldStop(signo))
+ {
+ 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 (signals.GetShouldNotify(signo))
+ m_stop_vote = eVoteYes;
+ else
+ m_stop_vote = eVoteNo;
+
+ return false;
+ }
+ }
+ default:
+ return true;
+ }
+
+ }
+
+ // If there's no explicit reason to stop, then we will continue.
+ return false;
+}
+
+bool
+ThreadPlanBase::StopOthers ()
+{
+ return false;
+}
+
+StateType
+ThreadPlanBase::RunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanBase::WillStop ()
+{
+ return true;
+}
+
+// The base plan is never done.
+bool
+ThreadPlanBase::MischiefManaged ()
+{
+ // The base plan is never done.
+ return false;
+}
+
diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp
new file mode 100644
index 00000000000..4b3533a3446
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -0,0 +1,250 @@
+//===-- 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
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.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
+//----------------------------------------------------------------------
+
+ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
+ Address &function,
+ lldb::addr_t arg,
+ bool stop_other_threads,
+ bool discard_on_error) :
+ ThreadPlan ("Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_valid(false),
+ m_process(thread.GetProcess()),
+ m_arg_addr (arg),
+ m_args (NULL),
+ m_thread(thread),
+ m_stop_other_threads(stop_other_threads)
+{
+
+ SetOkayToDiscard (discard_on_error);
+
+ Process& process = thread.GetProcess();
+ Target& target = process.GetTarget();
+ const ABI *abi = process.GetABI();
+
+ if (!abi)
+ return;
+
+ lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
+
+ SymbolContextList contexts;
+ SymbolContext context;
+ ModuleSP executableModuleSP (target.GetExecutableModule());
+
+ if (!executableModuleSP ||
+ !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
+ return;
+
+ contexts.GetContextAtIndex(0, context);
+
+ m_start_addr = context.symbol->GetValue();
+ lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&process);
+
+ if (!thread.SaveFrameZeroState(m_register_backup))
+ return;
+
+ m_function_addr = function;
+ lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&process);
+
+ if (!abi->PrepareTrivialCall(thread,
+ spBelowRedZone,
+ FunctionLoadAddr,
+ StartLoadAddr,
+ m_arg_addr))
+ return;
+
+ m_valid = true;
+}
+
+ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
+ Address &function,
+ ValueList &args,
+ bool stop_other_threads,
+ bool discard_on_error) :
+ ThreadPlan ("Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_valid(false),
+ m_process(thread.GetProcess()),
+ m_arg_addr (0),
+ m_args (&args),
+ m_thread(thread),
+ m_stop_other_threads(stop_other_threads)
+{
+
+ SetOkayToDiscard (discard_on_error);
+
+ Process& process = thread.GetProcess();
+ Target& target = process.GetTarget();
+ const ABI *abi = process.GetABI();
+
+ if(!abi)
+ return;
+
+ lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
+
+ SymbolContextList contexts;
+ SymbolContext context;
+ ModuleSP executableModuleSP (target.GetExecutableModule());
+
+ if (!executableModuleSP ||
+ !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
+ return;
+
+ contexts.GetContextAtIndex(0, context);
+
+ m_start_addr = context.symbol->GetValue();
+ lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&process);
+
+ if(!thread.SaveFrameZeroState(m_register_backup))
+ return;
+
+ m_function_addr = function;
+ lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&process);
+
+ if (!abi->PrepareNormalCall(thread,
+ spBelowRedZone,
+ FunctionLoadAddr,
+ StartLoadAddr,
+ *m_args))
+ return;
+
+ m_valid = true;
+}
+
+ThreadPlanCallFunction::~ThreadPlanCallFunction ()
+{
+}
+
+void
+ThreadPlanCallFunction::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ {
+ s->Printf("Function call thread plan");
+ }
+ else
+ {
+ if (m_args)
+ s->Printf("Thread plan to call 0x%llx with parsed arguments", m_function_addr.GetLoadAddress(&m_process), m_arg_addr);
+ else
+ s->Printf("Thread plan to call 0x%llx void * argument at: 0x%llx", m_function_addr.GetLoadAddress(&m_process), m_arg_addr);
+ }
+}
+
+bool
+ThreadPlanCallFunction::ValidatePlan (Stream *error)
+{
+ if (!m_valid)
+ return false;
+
+ return true;
+}
+
+bool
+ThreadPlanCallFunction::PlanExplainsStop ()
+{
+ if (!m_subplan_sp)
+ return false;
+ else
+ return m_subplan_sp->PlanExplainsStop();
+}
+
+bool
+ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
+{
+ if (PlanExplainsStop())
+ {
+ m_thread.RestoreSaveFrameZero(m_register_backup);
+ m_thread.ClearStackFrames();
+ SetPlanComplete();
+ 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::RunState ()
+{
+ return eStateRunning;
+}
+
+void
+ThreadPlanCallFunction::DidPush ()
+{
+ m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
+
+ m_thread.QueueThreadPlan(m_subplan_sp, false);
+
+}
+
+bool
+ThreadPlanCallFunction::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanCallFunction::MischiefManaged ()
+{
+ if (IsPlanComplete())
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ if (log)
+ log->Printf("Completed call function plan.");
+
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
diff --git a/lldb/source/Target/ThreadPlanContinue.cpp b/lldb/source/Target/ThreadPlanContinue.cpp
new file mode 100644
index 00000000000..63d8a3323d0
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanContinue.cpp
@@ -0,0 +1,120 @@
+//===-- ThreadPlanContinue.cpp ----------------------------------*- 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/ThreadPlanContinue.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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanContinue: Continue plan
+//----------------------------------------------------------------------
+
+ThreadPlanContinue::ThreadPlanContinue (Thread &thread, bool stop_others, Vote stop_vote, Vote run_vote, bool immediate) :
+ ThreadPlan ("Continue after previous plan", thread, stop_vote, run_vote),
+ m_stop_others (stop_others),
+ m_did_run (false),
+ m_immediate (immediate)
+{
+}
+
+ThreadPlanContinue::~ThreadPlanContinue ()
+{
+}
+
+void
+ThreadPlanContinue::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf ("continue");
+ else
+ {
+ s->Printf ("Continue from the previous plan");
+ }
+}
+
+bool
+ThreadPlanContinue::ValidatePlan (Stream *error)
+{
+ // Since we read the instruction we're stepping over from the thread,
+ // this plan will always work.
+ return true;
+}
+
+bool
+ThreadPlanContinue::PlanExplainsStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanContinue::ShouldStop (Event *event_ptr)
+{
+ return false;
+}
+
+bool
+ThreadPlanContinue::IsImmediate () const
+{
+ return m_immediate;
+ return false;
+}
+
+bool
+ThreadPlanContinue::StopOthers ()
+{
+ return m_stop_others;
+}
+
+StateType
+ThreadPlanContinue::RunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanContinue::WillResume (StateType resume_state, bool current_plan)
+{
+ ThreadPlan::WillResume (resume_state, current_plan);
+ if (current_plan)
+ {
+ m_did_run = true;
+ }
+ return true;
+}
+
+bool
+ThreadPlanContinue::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanContinue::MischiefManaged ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ if (m_did_run)
+ {
+ if (log)
+ log->Printf("Completed continue plan.");
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ return false;
+}
diff --git a/lldb/source/Target/ThreadPlanRunToAddress.cpp b/lldb/source/Target/ThreadPlanRunToAddress.cpp
new file mode 100644
index 00000000000..0544ea5bcbe
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanRunToAddress.cpp
@@ -0,0 +1,176 @@
+//===-- 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 ("Run to breakpoint plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_stop_others (stop_others),
+ m_address (LLDB_INVALID_ADDRESS),
+ m_break_id (LLDB_INVALID_BREAK_ID)
+{
+ m_address = address.GetLoadAddress(&m_thread.GetProcess());
+ SetInitialBreakpoint();
+}
+
+ThreadPlanRunToAddress::ThreadPlanRunToAddress
+(
+ Thread &thread,
+ lldb::addr_t address,
+ bool stop_others
+) :
+ ThreadPlan ("Run to breakpoint plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_stop_others (stop_others),
+ m_address (address),
+ m_break_id (LLDB_INVALID_BREAK_ID)
+{
+ SetInitialBreakpoint();
+}
+
+void
+ThreadPlanRunToAddress::SetInitialBreakpoint ()
+{
+ Breakpoint *breakpoint;
+ breakpoint = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_address, true).get();
+ if (breakpoint != NULL)
+ {
+ m_break_id = breakpoint->GetID();
+ breakpoint->SetThreadID(m_thread.GetID());
+ }
+}
+
+ThreadPlanRunToAddress::~ThreadPlanRunToAddress ()
+{
+ if (m_break_id != LLDB_INVALID_BREAK_ID)
+ {
+ m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_break_id);
+ }
+}
+
+void
+ThreadPlanRunToAddress::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ {
+ s->Printf ("run to address: ");
+ s->Address (m_address, sizeof (addr_t));
+ }
+ else
+ {
+ s->Printf ("Run to address: ");
+ s->Address(m_address, sizeof (addr_t));
+ s->Printf (" using breakpoint: %d - ", m_break_id);
+ Breakpoint *breakpoint = m_thread.GetProcess().GetTarget().GetBreakpointByID (m_break_id).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.
+ if(m_break_id == LLDB_INVALID_BREAK_ID)
+ return false;
+ else
+ return true;
+}
+
+bool
+ThreadPlanRunToAddress::PlanExplainsStop ()
+{
+ 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::RunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanRunToAddress::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanRunToAddress::MischiefManaged ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ if (AtOurAddress())
+ {
+ // Remove the breakpoint
+ if (m_break_id != LLDB_INVALID_BREAK_ID)
+ {
+ m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_break_id);
+ m_break_id = 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();
+ return m_address == current_address;
+}
diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp
new file mode 100644
index 00000000000..493ab63bc33
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp
@@ -0,0 +1,53 @@
+//===-- 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/Thread.h"
+#include "lldb/Target/ThreadPlanShouldStopHere.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;
+}
+
+ThreadPlan *
+ThreadPlanShouldStopHere::InvokeShouldStopHereCallback ()
+{
+ if (m_callback)
+ return m_callback (m_owner, m_flags, m_baton);
+ else
+ return NULL;
+} \ No newline at end of file
diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp
new file mode 100644
index 00000000000..f62fdb87c7f
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepInRange.cpp
@@ -0,0 +1,154 @@
+//===-- 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/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepThrough.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 ("Step Range stepping in", thread, range, addr_context, stop_others),
+ ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL)
+{
+ 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): ");
+ m_address_range.Dump (s, &m_thread.GetProcess(), Address::DumpStyleLoadAddress);
+ }
+}
+
+bool
+ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ m_no_more_plans = false;
+
+ if (log)
+ {
+ StreamString s;
+ s.Address (m_thread.GetRegisterContext()->GetPC(), m_thread.GetProcess().GetAddressByteSize());
+ log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
+ }
+
+ // If we're still in the range, keep going.
+ if (InRange())
+ return false;
+
+ // If we're in an older frame then we should stop.
+ if (FrameIsOlder())
+ return true;
+
+ // See if we are in a place we should step through (i.e. a trampoline of some sort):
+ // 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 (!FrameIsYounger() && InSymbol())
+ {
+ SetPlanComplete();
+ return true;
+ }
+
+ ThreadPlan* new_plan = NULL;
+
+ bool stop_others;
+ if (m_stop_others == lldb::eOnlyThisThread)
+ stop_others = true;
+ else
+ stop_others = false;
+
+ new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
+ // 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 (!new_plan && FrameIsYounger())
+ new_plan = InvokeShouldStopHereCallback();
+
+ if (new_plan == NULL)
+ {
+ 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::SetDefaultFlagValue (uint32_t new_value)
+{
+ // TODO: Should we test this for sanity?
+ ThreadPlanStepInRange::s_default_flag_values = new_value;
+}
+
+ThreadPlan *
+ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
+{
+ if (flags.IsSet(eAvoidNoDebug))
+ {
+ StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
+
+ if (!frame->HasDebugInformation())
+ {
+ // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
+ return current_plan->GetThread().QueueThreadPlanForStepOut (false, NULL, true, current_plan->StopOthers(), eVoteNo, eVoteNoOpinion);
+ }
+ }
+
+ return NULL;
+}
diff --git a/lldb/source/Target/ThreadPlanStepInstruction.cpp b/lldb/source/Target/ThreadPlanStepInstruction.cpp
new file mode 100644
index 00000000000..41c4373105b
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepInstruction.cpp
@@ -0,0 +1,191 @@
+//===-- 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/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Process.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 ("Step over single instruction", thread, stop_vote, run_vote),
+ m_instruction_addr (0),
+ m_step_over (step_over),
+ m_stack_depth(0),
+ m_stop_other_threads (stop_other_threads)
+{
+ m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
+ m_stack_depth = m_thread.GetStackFrameCount();
+}
+
+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_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::PlanExplainsStop ()
+{
+ Thread::StopInfo info;
+ if (m_thread.GetStopInfo (&info))
+ {
+ StopReason reason = info.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);
+ if (m_thread.GetStackFrameCount() <= m_stack_depth)
+ {
+ 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 (log)
+ {
+ StreamString s;
+ s.PutCString ("Stepped in to: ");
+ addr_t stop_addr = m_thread.GetStackFrameAtIndex(0)->GetPC().GetLoadAddress(&m_thread.GetProcess());
+ s.Address (stop_addr, m_thread.GetProcess().GetAddressByteSize());
+ s.PutCString (" stepping out to: ");
+ addr_t return_addr = return_frame->GetPC().GetLoadAddress(&m_thread.GetProcess());
+ s.Address (return_addr, m_thread.GetProcess().GetAddressByteSize());
+ log->Printf("%s.", s.GetData());
+ }
+ m_thread.QueueThreadPlanForStepOut(false, NULL, true, m_stop_other_threads, eVoteNo, eVoteNoOpinion);
+ return false;
+ }
+ 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::RunState ()
+{
+ 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/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp
new file mode 100644
index 00000000000..e05a8a440a1
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepOut.cpp
@@ -0,0 +1,228 @@
+//===-- 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/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.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
+) :
+ ThreadPlan ("Step out", thread, stop_vote, run_vote),
+ m_step_from_context (context),
+ m_step_from_insn (LLDB_INVALID_ADDRESS),
+ m_return_addr (LLDB_INVALID_ADDRESS),
+ m_first_insn (first_insn),
+ m_return_bp_id(LLDB_INVALID_BREAK_ID),
+ m_stop_others (stop_others)
+{
+ m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
+
+ // Find the return address and set a breakpoint there:
+ // FIXME - can we do this more securely if we know first_insn?
+
+ StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
+ if (return_frame)
+ {
+ m_return_addr = return_frame->GetPC().GetLoadAddress(&m_thread.GetProcess());
+ Breakpoint *return_bp = m_thread.GetProcess().GetTarget().CreateBreakpoint (m_return_addr, true).get();
+ if (return_bp != NULL)
+ {
+ return_bp->SetThreadID(m_thread.GetID());
+ m_return_bp_id = return_bp->GetID();
+ }
+ else
+ {
+ m_return_bp_id = LLDB_INVALID_BREAK_ID;
+ }
+ }
+
+ m_stack_depth = m_thread.GetStackFrameCount();
+}
+
+ThreadPlanStepOut::~ThreadPlanStepOut ()
+{
+ if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
+ m_thread.GetProcess().GetTarget().RemoveBreakpointByID(m_return_bp_id);
+}
+
+void
+ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf ("step out");
+ else
+ {
+ s->Printf ("Stepping out from address 0x%llx to return address 0x%llx 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_return_bp_id == LLDB_INVALID_BREAK_ID)
+ return false;
+ else
+ return true;
+}
+
+bool
+ThreadPlanStepOut::PlanExplainsStop ()
+{
+ // We don't explain signals or breakpoints (breakpoints that handle stepping in or
+ // out will be handled by a child plan.
+ Thread::StopInfo info;
+ if (m_thread.GetStopInfo (&info))
+ {
+ StopReason reason = info.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 (info.GetBreakpointSiteID());
+ if (!this_site)
+ return false;
+
+ if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
+ {
+ // 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 (this_site->GetNumberOfOwners() == 1)
+ return true;
+ else
+ {
+ SetPlanComplete();
+ return false;
+ }
+ }
+ else
+ return false;
+ }
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ return false;
+ default:
+ return true;
+ }
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepOut::ShouldStop (Event *event_ptr)
+{
+ if (IsPlanComplete()
+ || m_thread.GetRegisterContext()->GetPC() == m_return_addr
+ || m_stack_depth > m_thread.GetStackFrameCount())
+ {
+ SetPlanComplete();
+ return true;
+ }
+ else
+ return false;
+}
+
+bool
+ThreadPlanStepOut::StopOthers ()
+{
+ return m_stop_others;
+}
+
+StateType
+ThreadPlanStepOut::RunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanStepOut::WillResume (StateType resume_state, bool current_plan)
+{
+ ThreadPlan::WillResume (resume_state, current_plan);
+ if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
+ return false;
+
+ if (current_plan)
+ {
+ Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get();
+ if (return_bp != NULL)
+ return_bp->SetEnabled (true);
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepOut::WillStop ()
+{
+ Breakpoint *return_bp = m_thread.GetProcess().GetTarget().GetBreakpointByID(m_return_bp_id).get();
+ if (return_bp != NULL)
+ return_bp->SetEnabled (false);
+ return true;
+}
+
+bool
+ThreadPlanStepOut::MischiefManaged ()
+{
+ if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
+ {
+ // If I couldn't set this breakpoint, then I'm just going to jettison myself.
+ return true;
+ }
+ else 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.");
+ m_thread.GetProcess().GetTarget().RemoveBreakpointByID (m_return_bp_id);
+ m_return_bp_id = LLDB_INVALID_BREAK_ID;
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
diff --git a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
new file mode 100644
index 00000000000..2b8b06d5960
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
@@ -0,0 +1,130 @@
+//===-- 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 ("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_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 %d at 0x%llx", m_breakpoint_site_id, (uint64_t)m_breakpoint_addr);
+}
+
+bool
+ThreadPlanStepOverBreakpoint::ValidatePlan (Stream *error)
+{
+ return true;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::PlanExplainsStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::ShouldStop (Event *event_ptr)
+{
+ return false;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::StopOthers ()
+{
+ return true;
+}
+
+StateType
+ThreadPlanStepOverBreakpoint::RunState ()
+{
+ return eStateStepping;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::WillResume (StateType resume_state, bool current_plan)
+{
+ ThreadPlan::WillResume (resume_state, 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().DisableBreakpoint (bp_site_sp.get());
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::WillStop ()
+{
+ BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByAddress (m_breakpoint_addr));
+ if (bp_site_sp)
+ m_thread.GetProcess().EnableBreakpoint (bp_site_sp.get());
+ 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.
+ BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByAddress (m_breakpoint_addr));
+ if (bp_site_sp)
+ m_thread.GetProcess().EnableBreakpoint (bp_site_sp.get());
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+}
+
diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp
new file mode 100644
index 00000000000..ea56412a010
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp
@@ -0,0 +1,119 @@
+//===-- 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/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepThrough.h"
+
+using namespace lldb_private;
+
+
+//----------------------------------------------------------------------
+// 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,
+ bool okay_to_discard
+) :
+ ThreadPlanStepRange ("Step range stepping over", thread, range, addr_context, stop_others)
+{
+ SetOkayToDiscard (okay_to_discard);
+}
+
+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): ");
+ m_address_range.Dump (s, &m_thread.GetProcess(), Address::DumpStyleLoadAddress);
+ }
+}
+
+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.GetProcess().GetAddressByteSize());
+ log->Printf("ThreadPlanStepOverRange reached %s.", s.GetData());
+ }
+
+ // If we're still in the range, keep going.
+ if (InRange())
+ return false;
+
+ // 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 step if we are forcing running one thread.
+ bool stop_others;
+ if (m_stop_others == lldb::eOnlyThisThread)
+ stop_others = true;
+ else
+ stop_others = false;
+
+ ThreadPlan* new_plan = NULL;
+
+ if (FrameIsOlder())
+ return true;
+ else if (FrameIsYounger())
+ {
+ new_plan = m_thread.QueueThreadPlanForStepOut (false, NULL, true, stop_others, lldb::eVoteNo, lldb::eVoteNoOpinion);
+ }
+ else 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 = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
+ }
+
+ if (new_plan == NULL)
+ m_no_more_plans = true;
+ else
+ m_no_more_plans = false;
+
+ if (new_plan == NULL)
+ {
+ // 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;
+}
diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp
new file mode 100644
index 00000000000..edf80a57d52
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepRange.cpp
@@ -0,0 +1,263 @@
+//===-- 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/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.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 (const char *name, Thread &thread, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_others) :
+ ThreadPlan (name, thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_address_range (range),
+ m_addr_context (addr_context),
+ m_stop_others (stop_others),
+ m_stack_depth (0),
+ m_no_more_plans (false),
+ m_stack_id (),
+ m_first_run_event (true)
+{
+ m_stack_depth = m_thread.GetStackFrameCount();
+ m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+}
+
+ThreadPlanStepRange::~ThreadPlanStepRange ()
+{
+}
+
+bool
+ThreadPlanStepRange::ValidatePlan (Stream *error)
+{
+ return true;
+}
+
+bool
+ThreadPlanStepRange::PlanExplainsStop ()
+{
+ // We don't explain signals or breakpoints (breakpoints that handle stepping in or
+ // out will be handled by a child plan.
+ Thread::StopInfo info;
+ if (m_thread.GetStopInfo (&info))
+ {
+ StopReason reason = info.GetStopReason();
+
+ switch (reason)
+ {
+ case eStopReasonBreakpoint:
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ return false;
+ default:
+ return true;
+ }
+ }
+ return true;
+}
+
+Vote
+ThreadPlanStepRange::ShouldReportStop (Event *event_ptr)
+{
+ if (IsPlanComplete())
+ return eVoteYes;
+ else
+ return eVoteNo;
+}
+
+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();
+
+ ret_value = m_address_range.ContainsLoadAddress(pc_load_addr, &m_thread.GetProcess());
+
+ 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)
+ && (m_addr_context.line_entry.line == new_context.line_entry.line))
+ {
+ m_addr_context = new_context;
+ m_address_range = m_addr_context.line_entry.range;
+ ret_value = true;
+ if (log)
+ {
+ StreamString s;
+ m_address_range.Dump (&s, &m_thread.GetProcess(), Address::DumpStyleLoadAddress);
+
+ log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
+ }
+ }
+ }
+
+ }
+
+ if (!ret_value && log)
+ log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr);
+
+ return ret_value;
+}
+
+bool
+ThreadPlanStepRange::InSymbol()
+{
+ lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
+ Process *process = m_thread.CalculateProcess();
+
+ if (m_addr_context.function != NULL)
+ {
+ return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, process);
+ }
+ else if (m_addr_context.symbol != NULL)
+ {
+ return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, process);
+ }
+ 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.
+
+bool
+ThreadPlanStepRange::FrameIsYounger ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ uint32_t current_depth = m_thread.GetStackFrameCount();
+ if (current_depth == m_stack_depth)
+ {
+ if (log)
+ log->Printf ("Step range FrameIsYounger still in start function.");
+ return false;
+ }
+ else if (current_depth < m_stack_depth)
+ {
+ if (log)
+ log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
+ return false;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
+ return true;
+ }
+}
+
+bool
+ThreadPlanStepRange::FrameIsOlder ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ uint32_t current_depth = m_thread.GetStackFrameCount();
+ if (current_depth == m_stack_depth)
+ {
+ if (log)
+ log->Printf ("Step range FrameIsOlder still in start function.");
+ return false;
+ }
+ else if (current_depth < m_stack_depth)
+ {
+ if (log)
+ log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
+ return true;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
+ return false;
+ }
+}
+
+bool
+ThreadPlanStepRange::StopOthers ()
+{
+ if (m_stop_others == lldb::eOnlyThisThread
+ || m_stop_others == lldb::eOnlyDuringStepping)
+ return true;
+ else
+ return false;
+}
+
+bool
+ThreadPlanStepRange::WillStop ()
+{
+ return true;
+}
+
+StateType
+ThreadPlanStepRange::RunState ()
+{
+ return eStateStepping;
+}
+
+bool
+ThreadPlanStepRange::MischiefManaged ()
+{
+ bool done = true;
+ if (!IsPlanComplete())
+ {
+ if (InRange())
+ {
+ done = false;
+ }
+ else if (!FrameIsOlder())
+ {
+ 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.");
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+}
diff --git a/lldb/source/Target/ThreadPlanStepThrough.cpp b/lldb/source/Target/ThreadPlanStepThrough.cpp
new file mode 100644
index 00000000000..5e614e5aa52
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepThrough.cpp
@@ -0,0 +1,137 @@
+//===-- 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/Process.h"
+#include "lldb/Target/RegisterContext.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, bool stop_others) :
+ ThreadPlan ("Step through trampolines and prologues", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_start_address (0),
+ m_stop_others (stop_others)
+{
+ m_start_address = GetThread().GetRegisterContext()->GetPC(0);
+}
+
+ThreadPlanStepThrough::~ThreadPlanStepThrough ()
+{
+}
+
+void
+ThreadPlanStepThrough::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf ("Step through");
+ else
+ {
+ s->Printf ("Stepping through trampoline code from: ");
+ s->Address(m_start_address, sizeof (addr_t));
+ }
+}
+
+bool
+ThreadPlanStepThrough::ValidatePlan (Stream *error)
+{
+ if (HappyToStopHere())
+ return false;
+ else
+ return true;
+}
+
+bool
+ThreadPlanStepThrough::PlanExplainsStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanStepThrough::ShouldStop (Event *event_ptr)
+{
+ return true;
+}
+
+bool
+ThreadPlanStepThrough::StopOthers ()
+{
+ return m_stop_others;
+}
+
+StateType
+ThreadPlanStepThrough::RunState ()
+{
+ return eStateStepping;
+}
+
+bool
+ThreadPlanStepThrough::WillResume (StateType resume_state, bool current_plan)
+{
+ ThreadPlan::WillResume(resume_state, current_plan);
+ if (current_plan)
+ {
+ ThreadPlanSP sub_plan_sp(m_thread.GetProcess().GetDynamicLoader()->GetStepThroughTrampolinePlan (m_thread, m_stop_others));
+ if (sub_plan_sp != NULL)
+ PushPlan (sub_plan_sp);
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepThrough::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanStepThrough::MischiefManaged ()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ // Stop if we're happy with the place we've landed...
+
+ if (!HappyToStopHere())
+ {
+ // If we are still at the PC we were trying to step over.
+ return false;
+ }
+ else
+ {
+ if (log)
+ log->Printf("Completed step through step plan.");
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+}
+
+bool
+ThreadPlanStepThrough::HappyToStopHere()
+{
+ // This should again ask the various trampolines whether we are still at a
+ // trampoline point, and if so, continue through the possibly nested trampolines.
+
+ return true;
+}
+
diff --git a/lldb/source/Target/ThreadPlanStepUntil.cpp b/lldb/source/Target/ThreadPlanStepUntil.cpp
new file mode 100644
index 00000000000..3f9cdb55047
--- /dev/null
+++ b/lldb/source/Target/ThreadPlanStepUntil.cpp
@@ -0,0 +1,360 @@
+//===-- 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/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
+) :
+ ThreadPlan ("Step out", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_step_from_insn (LLDB_INVALID_ADDRESS),
+ m_return_addr (LLDB_INVALID_ADDRESS),
+ m_return_bp_id(LLDB_INVALID_BREAK_ID),
+ m_stepped_out(false),
+ m_should_stop(false),
+ m_explains_stop(false),
+ m_ran_analyze (false),
+ m_stop_others (stop_others)
+{
+
+ SetOkayToDiscard(true);
+ // Stash away our "until" addresses:
+ Target &target = m_thread.GetProcess().GetTarget();
+
+ m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
+ 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?
+
+ StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
+ m_return_addr = return_frame->GetPC().GetLoadAddress(&m_thread.GetProcess());
+ Breakpoint *return_bp = target.CreateBreakpoint (m_return_addr, true).get();
+ if (return_bp != NULL)
+ {
+ return_bp->SetThreadID(thread_id);
+ m_return_bp_id = return_bp->GetID();
+ }
+ else
+ {
+ m_return_bp_id = LLDB_INVALID_BREAK_ID;
+ }
+
+ m_stack_depth = m_thread.GetStackFrameCount();
+
+ // Now set breakpoints on all our return addresses:
+ for (int i = 0; i < num_addresses; i++)
+ {
+ Breakpoint *until_bp = target.CreateBreakpoint (address_list[i], true).get();
+ if (until_bp != NULL)
+ {
+ until_bp->SetThreadID(thread_id);
+ m_until_points[address_list[i]] = until_bp->GetID();
+ }
+ else
+ {
+ m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
+ }
+ }
+}
+
+ThreadPlanStepUntil::~ThreadPlanStepUntil ()
+{
+ Clear();
+}
+
+void
+ThreadPlanStepUntil::Clear()
+{
+ Target &target = m_thread.GetProcess().GetTarget();
+ if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
+ {
+ target.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.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%llx until we reach 0x%llx 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%llx until we reach one of:",
+ (uint64_t)m_step_from_insn);
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ s->Printf ("\n\t0x%llx (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
+ }
+ }
+ s->Printf(" stepped out address is 0x%lx.", (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;
+
+ Thread::StopInfo info;
+ m_should_stop = true;
+ m_explains_stop = false;
+
+ if (m_thread.GetStopInfo (&info))
+ {
+ StopReason reason = info.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 (info.GetBreakpointSiteID());
+ 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".
+ if (m_stack_depth > m_thread.GetStackFrameCount())
+ {
+ 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.
+ if (m_stack_depth == m_thread.GetStackFrameCount())
+ 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:
+ m_explains_stop = false;
+ break;
+ default:
+ m_explains_stop = true;
+ break;
+ }
+ }
+}
+
+bool
+ThreadPlanStepUntil::PlanExplainsStop ()
+{
+ // 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.
+
+ Thread::StopInfo stop_info (&m_thread);
+ if (!m_thread.GetStopInfo(&stop_info)
+ || stop_info.GetStopReason() == eStopReasonNone)
+ return false;
+
+ AnalyzeStop();
+ return m_should_stop;
+}
+
+bool
+ThreadPlanStepUntil::StopOthers ()
+{
+ return m_stop_others;
+}
+
+StateType
+ThreadPlanStepUntil::RunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanStepUntil::WillResume (StateType resume_state, bool current_plan)
+{
+ ThreadPlan::WillResume (resume_state, current_plan);
+ if (current_plan)
+ {
+ Target &target = m_thread.GetProcess().GetTarget();
+ Breakpoint *return_bp = target.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.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 ()
+{
+ Target &target = m_thread.GetProcess().GetTarget();
+ Breakpoint *return_bp = target.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.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/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp
new file mode 100644
index 00000000000..e6500c5dba8
--- /dev/null
+++ b/lldb/source/Target/UnixSignals.cpp
@@ -0,0 +1,310 @@
+//===-- 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
+
+using namespace lldb_private;
+
+UnixSignals::Signal::Signal (const char *name, bool default_suppress, bool default_stop, bool default_notify) :
+ m_name (name),
+ m_conditions ()
+{
+ m_conditions[Signal::eCondSuppress] = default_suppress;
+ m_conditions[Signal::eCondStop] = default_stop;
+ m_conditions[Signal::eCondNotify] = default_notify;
+}
+
+//----------------------------------------------------------------------
+// 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();
+
+ AddSignal(1, "SIGHUP", false, true, true ); // 1 hangup
+ AddSignal(2, "SIGINT", true, true, true ); // 2 interrupt
+ AddSignal(3, "SIGQUIT", false, true, true ); // 3 quit
+ AddSignal(4, "SIGILL", false, true, true ); // 4 illegal instruction (not reset when caught)
+ AddSignal(5, "SIGTRAP", true, true, true ); // 5 trace trap (not reset when caught)
+ AddSignal(6, "SIGABRT", false, true, true ); // 6 abort()
+ AddSignal(7, "SIGEMT", false, true, true ); // 7 pollable event ([XSR] generated, not supported)
+ AddSignal(8, "SIGFPE", false, true, true ); // 8 floating point exception
+ AddSignal(9, "SIGKILL", false, true, true ); // 9 kill (cannot be caught or ignored)
+ AddSignal(10, "SIGBUS", false, true, true ); // 10 bus error
+ AddSignal(11, "SIGSEGV", false, true, true ); // 11 segmentation violation
+ AddSignal(12, "SIGSYS", false, true, true ); // 12 bad argument to system call
+ AddSignal(13, "SIGPIPE", false, true, true ); // 13 write on a pipe with no one to read it
+ AddSignal(14, "SIGALRM", false, false, true ); // 14 alarm clock
+ AddSignal(15, "SIGTERM", false, true, true ); // 15 software termination signal from kill
+ AddSignal(16, "SIGURG", false, false, false); // 16 urgent condition on IO channel
+ AddSignal(17, "SIGSTOP", false, true, true ); // 17 sendable stop signal not from tty
+ AddSignal(18, "SIGTSTP", false, true, true ); // 18 stop signal from tty
+ AddSignal(19, "SIGCONT", false, true, true ); // 19 continue a stopped process
+ AddSignal(20, "SIGCHLD", false, false, true ); // 20 to parent on child stop or exit
+ AddSignal(21, "SIGTTIN", false, true, true ); // 21 to readers pgrp upon background tty read
+ AddSignal(22, "SIGTTOU", false, true, true ); // 22 like TTIN for output if (tp->t_local&LTOSTOP)
+ AddSignal(23, "SIGIO", false, false, false); // 23 input/output possible signal
+ AddSignal(24, "SIGXCPU", false, true, true ); // 24 exceeded CPU time limit
+ AddSignal(25, "SIGXFSZ", false, true, true ); // 25 exceeded file size limit
+ AddSignal(26, "SIGVTALRM", false, false, false); // 26 virtual time alarm
+ AddSignal(27, "SIGPROF", false, false, false); // 27 profiling time alarm
+ AddSignal(28, "SIGWINCH", false, false, false); // 28 window size changes
+ AddSignal(29, "SIGINFO", false, true, true ); // 29 information request
+ AddSignal(30, "SIGUSR1", false, true, true ); // 30 user defined signal 1
+ AddSignal(31, "SIGUSR2", false, true, true ); // 31 user defined signal 2
+}
+void
+UnixSignals::AddSignal (int signo, const char *name, bool default_suppress, bool default_stop, bool default_notify)
+{
+ collection::iterator iter = m_signals.find (signo);
+ struct Signal new_signal (name, default_suppress, default_stop, default_notify);
+
+ if (iter != m_signals.end())
+ m_signals.erase (iter);
+
+ m_signals.insert (iter, collection::value_type (signo, new_signal));
+}
+
+void
+UnixSignals::RemoveSignal (int signo)
+{
+ collection::iterator pos = m_signals.find (signo);
+ if (pos != m_signals.end())
+ m_signals.erase (pos);
+}
+
+UnixSignals::Signal *
+UnixSignals::GetSignalByName (const char *name, int32_t &signo)
+{
+ ConstString const_name (name);
+
+ collection::iterator pos, end = m_signals.end ();
+ for (pos = m_signals.begin (); pos != end; pos++)
+ {
+ if (const_name == (*pos).second.m_name)
+ {
+ signo = (*pos).first;
+ return &((*pos).second);
+ }
+ }
+ return NULL;
+}
+
+
+const UnixSignals::Signal *
+UnixSignals::GetSignalByName (const char *name, int32_t &signo) 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)
+ {
+ signo = (*pos).first;
+ return &((*pos).second);
+ }
+ }
+ return NULL;
+}
+
+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
+{
+ int32_t signo;
+ const Signal *signal = GetSignalByName (name, signo);
+ if (signal == NULL)
+ return LLDB_INVALID_SIGNAL_NUMBER;
+ else
+ return signo;
+}
+
+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_conditions[Signal::eCondSuppress];
+ should_stop = signal.m_conditions[Signal::eCondStop];
+ should_notify = signal.m_conditions[Signal::eCondNotify];
+ return signal.m_name.AsCString("");
+ }
+}
+
+bool
+UnixSignals::GetCondition
+(
+ int32_t signo,
+ UnixSignals::Signal::Condition cond_pos
+) const
+{
+ collection::const_iterator pos = m_signals.find (signo);
+ if (pos == m_signals.end())
+ return false;
+ else
+ return (*pos).second.m_conditions[cond_pos];
+}
+
+bool
+UnixSignals::SetCondition (int32_t signo, UnixSignals::Signal::Condition cond_pos, bool value)
+{
+ collection::iterator pos = m_signals.find (signo);
+ if (pos == m_signals.end())
+ return false;
+ else
+ {
+ bool ret_value = (*pos).second.m_conditions[cond_pos];
+ (*pos).second.m_conditions[cond_pos] = value;
+ return ret_value;
+ }
+}
+
+bool
+UnixSignals::SetCondition (const char *signal_name, UnixSignals::Signal::Condition cond_pos, bool value)
+{
+ int32_t signo;
+ Signal *signal = GetSignalByName (signal_name, signo);
+ if (signal == NULL)
+ return false;
+ else
+ {
+ bool ret_value = signal->m_conditions[cond_pos];
+ signal->m_conditions[cond_pos] = value;
+ return ret_value;
+ }
+}
+
+bool
+UnixSignals::GetShouldSuppress (int signo) const
+{
+ return GetCondition (signo, Signal::eCondSuppress);
+}
+
+bool
+UnixSignals::SetShouldSuppress (int signo, bool value)
+{
+ return SetCondition (signo, Signal::eCondSuppress, value);
+}
+
+bool
+UnixSignals::SetShouldSuppress (const char *signal_name, bool value)
+{
+ return SetCondition (signal_name, Signal::eCondSuppress, value);
+}
+
+bool
+UnixSignals::GetShouldStop (int signo) const
+{
+ return GetCondition (signo, Signal::eCondStop);
+}
+
+bool
+UnixSignals::SetShouldStop (int signo, bool value)
+{
+ return SetCondition (signo, Signal::eCondStop, value);
+}
+
+bool
+UnixSignals::SetShouldStop (const char *signal_name, bool value)
+{
+ return SetCondition (signal_name, Signal::eCondStop, value);
+}
+
+bool
+UnixSignals::GetShouldNotify (int signo) const
+{
+ return GetCondition (signo, Signal::eCondNotify);
+}
+
+bool
+UnixSignals::SetShouldNotify (int signo, bool value)
+{
+ return SetCondition (signo, Signal::eCondNotify, value);
+}
+
+bool
+UnixSignals::SetShouldNotify (const char *signal_name, bool value)
+{
+ return SetCondition (signal_name, Signal::eCondNotify, value);
+}
diff --git a/lldb/source/Utility/ARM_DWARF_Registers.h b/lldb/source/Utility/ARM_DWARF_Registers.h
new file mode 100644
index 00000000000..40b973be6da
--- /dev/null
+++ b/lldb/source/Utility/ARM_DWARF_Registers.h
@@ -0,0 +1,190 @@
+//===-- 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_
+
+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
+};
+
+#endif utility_ARM_DWARF_Registers_h_
+
diff --git a/lldb/source/Utility/ARM_GCC_Registers.h b/lldb/source/Utility/ARM_GCC_Registers.h
new file mode 100644
index 00000000000..fe1327b5e14
--- /dev/null
+++ b/lldb/source/Utility/ARM_GCC_Registers.h
@@ -0,0 +1,35 @@
+//===-- 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
+};
+
+#endif utility_ARM_GCC_Registers_h_
+
diff --git a/lldb/source/Utility/PseudoTerminal.cpp b/lldb/source/Utility/PseudoTerminal.cpp
new file mode 100644
index 00000000000..9bbecae6e6d
--- /dev/null
+++ b/lldb/source/Utility/PseudoTerminal.cpp
@@ -0,0 +1,336 @@
+//===-- 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 "PseudoTerminal.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+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/lldb/source/Utility/PseudoTerminal.h b/lldb/source/Utility/PseudoTerminal.h
new file mode 100644
index 00000000000..5d680745a32
--- /dev/null
+++ b/lldb/source/Utility/PseudoTerminal.h
@@ -0,0 +1,267 @@
+//===-- 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 <termios.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.
+ //------------------------------------------------------------------
+ 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/lldb/source/Utility/StringExtractor.cpp b/lldb/source/Utility/StringExtractor.cpp
new file mode 100644
index 00000000000..d2f69f95b7c
--- /dev/null
+++ b/lldb/source/Utility/StringExtractor.cpp
@@ -0,0 +1,360 @@
+//===-- 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 "StringExtractor.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+static inline int
+xdigit_to_sint (char ch)
+{
+ ch = tolower(ch);
+ if (ch >= 'a' && ch <= 'f')
+ return 10 + ch - 'a';
+ return ch - '0';
+}
+
+static inline unsigned int
+xdigit_to_uint (uint8_t ch)
+{
+ ch = tolower(ch);
+ 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 = UINT32_MAX;
+ return fail_value;
+}
+
+uint32_t
+StringExtractor::GetNumHexASCIICharsAtFilePos (uint32_t max) const
+{
+ uint32_t idx = m_index;
+ const size_t size = m_packet.size();
+ while (idx < size && idx - m_index < max && isxdigit(m_packet[idx]))
+ ++idx;
+ return idx - m_index;
+}
+//----------------------------------------------------------------------
+// Extract a signed character from two hex ASCII chars in the packet
+// string
+//----------------------------------------------------------------------
+int8_t
+StringExtractor::GetHexS8 (int8_t fail_value)
+{
+ if (GetNumHexASCIICharsAtFilePos(2))
+ {
+ char hi_nibble_char = m_packet[m_index];
+ char lo_nibble_char = m_packet[m_index+1];
+
+ if (isxdigit(hi_nibble_char) && isxdigit(lo_nibble_char))
+ {
+ char hi_nibble = xdigit_to_sint (hi_nibble_char);
+ char lo_nibble = xdigit_to_sint (lo_nibble_char);
+ m_index += 2;
+ return (hi_nibble << 4) + lo_nibble;
+ }
+ }
+ m_index = UINT32_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)
+{
+ if (GetNumHexASCIICharsAtFilePos(2))
+ {
+ uint8_t hi_nibble_char = m_packet[m_index];
+ uint8_t lo_nibble_char = m_packet[m_index+1];
+
+ if (isxdigit(hi_nibble_char) && isxdigit(lo_nibble_char))
+ {
+ uint8_t hi_nibble = xdigit_to_sint (hi_nibble_char);
+ uint8_t lo_nibble = xdigit_to_sint (lo_nibble_char);
+ m_index += 2;
+ return (hi_nibble << 4) + lo_nibble;
+ }
+ }
+ m_index = UINT32_MAX;
+ 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 = UINT32_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 = UINT32_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 = UINT32_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 = UINT32_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 && m_index != UINT32_MAX;
+ ++i, shift_amount += 8)
+ {
+ result |= ((uint64_t)GetHexU8() << shift_amount);
+ }
+ }
+ else
+ {
+ // Big Endian
+ for (i = 0; i < byte_size && m_index != UINT32_MAX; ++i)
+ {
+ result <<= 8;
+ result |= GetHexU8();
+ }
+ }
+ }
+ m_index = UINT32_MAX;
+ return fail_value;
+}
+
+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 = UINT32_MAX;
+ return false;
+}
diff --git a/lldb/source/Utility/StringExtractor.h b/lldb/source/Utility/StringExtractor.h
new file mode 100644
index 00000000000..e2312f71ad7
--- /dev/null
+++ b/lldb/source/Utility/StringExtractor.h
@@ -0,0 +1,126 @@
+//===-- 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>
+
+// 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 != UINT32_MAX;
+ }
+
+ uint32_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;
+ }
+
+ bool
+ Empty()
+ {
+ return m_packet.empty();
+ }
+
+ uint32_t
+ GetBytesLeft ()
+ {
+ if (m_index < m_packet.size())
+ return m_packet.size() - m_index;
+ return 0;
+ }
+ char
+ GetChar (char fail_value = '\0');
+
+ int8_t
+ GetHexS8 (int8_t fail_value = 0);
+
+ uint8_t
+ GetHexU8 (uint8_t fail_value = 0);
+
+ bool
+ GetNameColonValue (std::string &name, std::string &value);
+
+ 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);
+
+protected:
+ //------------------------------------------------------------------
+ // For StringExtractor only
+ //------------------------------------------------------------------
+ std::string m_packet; // The string in which to extract data.
+ uint32_t m_index; // When extracting data from a packet, this index
+ // will march along as things get extracted. If set
+ // to UINT32_MAX the end of the packet data was
+ // reached when decoding information
+
+ uint32_t
+ GetNumHexASCIICharsAtFilePos (uint32_t max = UINT32_MAX) const;
+};
+
+#endif // utility_StringExtractor_h_
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
new file mode 100644
index 00000000000..f7dcc4181f3
--- /dev/null
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -0,0 +1,89 @@
+//===-- StringExtractorGDBRemote.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StringExtractorGDBRemote.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+
+
+StringExtractorGDBRemote::Type
+StringExtractorGDBRemote::GetType () 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;
+}
+
+bool
+StringExtractorGDBRemote::IsOKPacket() const
+{
+ return GetType () == eOK;
+}
+
+
+bool
+StringExtractorGDBRemote::IsUnsupportedPacket() const
+{
+ return GetType () == eUnsupported;
+}
+
+bool
+StringExtractorGDBRemote::IsNormalPacket() const
+{
+ return GetType () == eResponse;
+}
+
+bool
+StringExtractorGDBRemote::IsErrorPacket() const
+{
+ return GetType () == eError &&
+ m_packet.size() == 3 &&
+ isxdigit(m_packet[1]) &&
+ isxdigit(m_packet[2]);
+}
+
+uint8_t
+StringExtractorGDBRemote::GetError ()
+{
+ if (GetType() == eError)
+ {
+ SetFilePos(1);
+ return GetHexU8(255);
+ }
+ return 0;
+}
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.h b/lldb/source/Utility/StringExtractorGDBRemote.h
new file mode 100644
index 00000000000..813ddad2e27
--- /dev/null
+++ b/lldb/source/Utility/StringExtractorGDBRemote.h
@@ -0,0 +1,73 @@
+//===-- 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 "StringExtractor.h"
+
+class StringExtractorGDBRemote : public StringExtractor
+{
+public:
+
+ StringExtractorGDBRemote() :
+ StringExtractor ()
+ {
+ }
+
+ StringExtractorGDBRemote(const char *cstr) :
+ StringExtractor (cstr)
+ {
+ }
+ StringExtractorGDBRemote(const StringExtractorGDBRemote& rhs) :
+ StringExtractor (rhs)
+ {
+ }
+
+ virtual ~StringExtractorGDBRemote()
+ {
+ }
+
+ enum Type
+ {
+ eUnsupported = 0,
+ eAck,
+ eNack,
+ eError,
+ eOK,
+ eResponse
+ };
+
+ StringExtractorGDBRemote::Type
+ GetType () const;
+
+ bool
+ IsOKPacket() const;
+
+ bool
+ IsUnsupportedPacket() const;
+
+ bool
+ IsNormalPacket () const;
+
+ bool
+ IsErrorPacket() 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/lldb/source/lldb-log.cpp b/lldb/source/lldb-log.cpp
new file mode 100644
index 00000000000..118a5b30632
--- /dev/null
+++ b/lldb/source/lldb-log.cpp
@@ -0,0 +1,190 @@
+//===-- 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/Core/Args.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamFile.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static Log *
+LogAccessor (bool get, StreamSP *stream_sp_ptr)
+{
+ static Log* g_log = NULL; // Leak for now as auto_ptr was being cleaned up
+ // by global constructors before other threads
+ // were done with it.
+ if (!get)
+ {
+ if (g_log)
+ delete g_log;
+ if (stream_sp_ptr)
+ g_log = new Log (*stream_sp_ptr);
+ else
+ g_log = NULL;
+ }
+
+ return g_log;
+
+}
+
+uint32_t
+lldb_private::GetLogMask ()
+{
+ Log *log = LogAccessor (true, NULL);
+ if (log)
+ return log->GetMask().GetAllFlagBits();
+ return 0;
+}
+
+bool
+lldb_private::IsLogVerbose ()
+{
+ uint32_t mask = GetLogMask();
+ return (mask & LIBLLDB_LOG_VERBOSE);
+}
+
+Log *
+lldb_private::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log = LogAccessor (true, NULL);
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().GetAllFlagBits();
+ 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 = LogAccessor (true, NULL);
+ if (log && mask && (mask & log->GetMask().GetAllFlagBits()))
+ return log;
+ return NULL;
+}
+
+void
+lldb_private::DisableLog ()
+{
+ LogAccessor (false, NULL);
+}
+
+
+Log *
+lldb_private::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, Args &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;
+ Log* log = LogAccessor (true, NULL);
+ if (log)
+ flag_bits = log->GetMask().GetAllFlagBits();
+ else
+ flag_bits = 0;
+
+ // Now make a new log with this stream.
+ log = LogAccessor (false, &log_stream_sp);
+ if (log)
+ {
+ bool got_unknown_category = false;
+ const size_t argc = args.GetArgumentCount();
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *arg = args.GetArgumentAtIndex(i);
+
+ if (strcasecmp(arg, "all") == 0 ) flag_bits |= LIBLLDB_LOG_ALL;
+ else if (strcasestr(arg, "break") == arg) flag_bits |= LIBLLDB_LOG_BREAKPOINTS;
+ else if (strcasecmp(arg, "default") == 0 ) flag_bits |= LIBLLDB_LOG_DEFAULT;
+ else if (strcasestr(arg, "event") == arg) flag_bits |= LIBLLDB_LOG_EVENTS;
+ else if (strcasestr(arg, "expr") == arg) flag_bits |= LIBLLDB_LOG_EXPRESSIONS;
+ else if (strcasestr(arg, "object") == arg) flag_bits |= LIBLLDB_LOG_OBJECT;
+ else if (strcasecmp(arg, "process") == 0 ) flag_bits |= LIBLLDB_LOG_PROCESS;
+ else if (strcasecmp(arg, "shlib") == 0 ) flag_bits |= LIBLLDB_LOG_SHLIB;
+ else if (strcasecmp(arg, "state") == 0 ) flag_bits |= LIBLLDB_LOG_STATE;
+ else if (strcasecmp(arg, "step") == 0 ) flag_bits |= LIBLLDB_LOG_STEP;
+ else if (strcasecmp(arg, "thread") == 0 ) flag_bits |= LIBLLDB_LOG_THREAD;
+ else if (strcasecmp(arg, "verbose") == 0 ) flag_bits |= LIBLLDB_LOG_VERBOSE;
+ else if (strcasestr(arg, "watch") == arg) flag_bits |= LIBLLDB_LOG_WATCHPOINTS;
+ else if (strcasestr(arg, "temp") == arg) flag_bits |= LIBLLDB_LOG_TEMPORARY;
+ else if (strcasestr(arg, "comm") == arg) flag_bits |= LIBLLDB_LOG_COMMUNICATION;
+ else if (strcasestr(arg, "conn") == arg) flag_bits |= LIBLLDB_LOG_CONNECTION;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListLogCategories (feedback_strm);
+ return log;
+ }
+ }
+ }
+
+ log->GetMask().SetAllFlagBits(flag_bits);
+ log->GetOptions().SetAllFlagBits(log_options);
+ }
+ return log;
+}
+
+
+void
+lldb_private::ListLogCategories (Stream *strm)
+{
+ strm->Printf("Logging categories for 'lldb':\n"
+ "\tall - turn on all available logging categories\n"
+ "\tdefault - enable the default set of logging categories for liblldb\n"
+ "\tbreak - log breakpoints\n"
+ "\tevents - log broadcaster, listener and event queue activities\n"
+ "\texpr - log expressions\n"
+ "\tobject - log object construction/destruction for important objects\n"
+ "\tprocess - log process events and activities\n"
+ "\tthread - log thread events and activities\n"
+ "\tshlib - log shared library related activities\n"
+ "\tstate - log private and public process state changes\n"
+ "\tstep - log step related activities\n"
+ "\tverbose - enable verbose loggging\n"
+ "\twatch - log watchpoint related activities\n");
+}
diff --git a/lldb/source/lldb.cpp b/lldb/source/lldb.cpp
new file mode 100644
index 00000000000..187f9ea3afb
--- /dev/null
+++ b/lldb/source/lldb.cpp
@@ -0,0 +1,107 @@
+//===-- 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-private.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "ABIMacOSX_i386.h"
+#include "ABISysV_x86_64.h"
+#include "DisassemblerLLVM.h"
+#include "DynamicLoaderMacOSXDYLD.h"
+#include "ObjectContainerBSDArchive.h"
+#include "ObjectContainerUniversalMachO.h"
+#include "ObjectFileELF.h"
+#include "ObjectFileMachO.h"
+#include "ProcessMacOSX.h"
+#include "ProcessGDBRemote.h"
+#include "SymbolFileDWARF.h"
+#include "SymbolFileDWARFDebugMap.h"
+#include "SymbolFileSymtab.h"
+#include "SymbolVendorMacOSX.h"
+
+using namespace lldb_private;
+
+
+void
+lldb_private::Initialize ()
+{
+ // Make sure we inialize only once
+ static Mutex g_inited_mutex(Mutex::eMutexTypeNormal);
+ static bool g_inited = false;
+
+ Mutex::Locker locker(g_inited_mutex);
+ if (!g_inited)
+ {
+ g_inited = true;
+ Timer::Initialize ();
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ Log::Callbacks log_callbacks = { DisableLog, EnableLog, ListLogCategories };
+
+ Log::RegisterLogChannel ("lldb", log_callbacks);
+ ABIMacOSX_i386::Initialize();
+ ABISysV_x86_64::Initialize();
+ DisassemblerLLVM::Initialize();
+ DynamicLoaderMacOSXDYLD::Initialize();
+ ObjectContainerUniversalMachO::Initialize();
+ ObjectContainerBSDArchive::Initialize();
+ ObjectFileELF::Initialize();
+ ObjectFileMachO::Initialize();
+ ProcessGDBRemote::Initialize();
+ ProcessMacOSX::Initialize();
+ SymbolFileDWARF::Initialize();
+ SymbolFileDWARFDebugMap::Initialize();
+ SymbolFileSymtab::Initialize();
+ SymbolVendorMacOSX::Initialize();
+ }
+}
+
+void
+lldb_private::WillTerminate()
+{
+ Host::WillTerminate();
+}
+
+void
+lldb_private::Terminate ()
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+ DisassemblerLLVM::Terminate();
+ DynamicLoaderMacOSXDYLD::Terminate();
+ ObjectContainerUniversalMachO::Terminate();
+ ObjectContainerBSDArchive::Terminate();
+ ObjectFileELF::Terminate();
+ ObjectFileMachO::Terminate();
+ ProcessGDBRemote::Terminate();
+ ProcessMacOSX::Terminate();
+ SymbolFileDWARF::Terminate();
+ SymbolFileDWARFDebugMap::Terminate();
+ SymbolFileSymtab::Terminate();
+ SymbolVendorMacOSX::Terminate();
+}
+
+const char *
+lldb_private::GetVersion ()
+{
+ extern const double LLDBVersionNumber;
+ static char g_version_string[32];
+ if (g_version_string[0] == '\0')
+ ::snprintf (g_version_string, sizeof(g_version_string), "LLDB-%g", LLDBVersionNumber);
+
+ return g_version_string;
+}
+
+ArchSpec &
+lldb_private::GetDefaultArchitecture ()
+{
+ static ArchSpec g_default_arch;
+ return g_default_arch;
+}
diff --git a/lldb/test/Makefile b/lldb/test/Makefile
new file mode 100644
index 00000000000..2221a23319e
--- /dev/null
+++ b/lldb/test/Makefile
@@ -0,0 +1,21 @@
+.PHONY: clean all
+
+#----------------------------------------------------------------------
+# Make all of the test programs
+#----------------------------------------------------------------------
+all:
+ find . -type d -depth 1 | xargs -J % find % \
+ -name Makefile \
+ -exec echo \; \
+ -exec echo make -f '{}' \; \
+ -execdir make \;
+
+#----------------------------------------------------------------------
+# Make all of the test programs
+#----------------------------------------------------------------------
+clean:
+ find . -type d -depth 1 | xargs -J % find % \
+ -name Makefile \
+ -exec echo \; \
+ -exec echo make -f '{}' clean \; \
+ -execdir make clean \;
diff --git a/lldb/test/array_types/Makefile b/lldb/test/array_types/Makefile
new file mode 100644
index 00000000000..7c8745b2ab1
--- /dev/null
+++ b/lldb/test/array_types/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=main.c
+CXX_SOURCES :=
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/array_types/cmds.txt b/lldb/test/array_types/cmds.txt
new file mode 100644
index 00000000000..8feebe21204
--- /dev/null
+++ b/lldb/test/array_types/cmds.txt
@@ -0,0 +1,3 @@
+break main.c:42
+continue
+var
diff --git a/lldb/test/array_types/main.c b/lldb/test/array_types/main.c
new file mode 100644
index 00000000000..b6eaf4b0d54
--- /dev/null
+++ b/lldb/test/array_types/main.c
@@ -0,0 +1,51 @@
+//===-- main.c --------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+int main (int argc, char const *argv[])
+{
+ struct point_tag {
+ int x;
+ int y;
+ };
+
+ struct rect_tag {
+ struct point_tag bottom_left;
+ struct point_tag top_right;
+ };
+ char char_16[16] = "Hello World\n";
+ char *strings[] = { "Hello", "Hola", "Bonjour", "Guten Tag" };
+ char char_matrix[3][3] = {{'a', 'b', 'c' }, {'d', 'e', 'f' }, {'g', 'h', 'i' }};
+ char char_matrix_matrix[3][2][3] =
+ { {{'a', 'b', 'c' }, {'d', 'e', 'f' }},
+ {{'A', 'B', 'C' }, {'D', 'E', 'F' }},
+ {{'1', '2', '3' }, {'4', '5', '6' }}};
+ short short_4[4] = { 1,2,3,4 };
+ short short_matrix[1][2] = { {1,2} };
+ unsigned short ushort_4[4] = { 1,2,3,4 };
+ short ushort_matrix[2][3] = {
+ { 1, 2, 3},
+ {11,22,33}
+ };
+ int int_2[2] = { 1, 2 };
+ unsigned int uint_2[2] = { 1, 2 };
+ long long_6[6] = { 1, 2, 3, 4, 5, 6 };
+ unsigned long ulong_6[6] = { 1, 2, 3, 4, 5, 6 };
+ struct point_tag points_2[2] = {
+ {1,2},
+ {3,4}
+ };
+ struct point_tag points_2_4_matrix[2][4] = {
+ {{ 1, 2}, { 3, 4}, { 5, 6}, { 7, 8}},
+ {{11,22}, {33,44}, {55,66}, {77,88}}
+ };
+ struct rect_tag rects_2[2] = {
+ {{1,2}, {3,4}},
+ {{5,6}, {7,8}}
+ };
+ return 0;
+}
diff --git a/lldb/test/bitfields/Makefile b/lldb/test/bitfields/Makefile
new file mode 100644
index 00000000000..7c8745b2ab1
--- /dev/null
+++ b/lldb/test/bitfields/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=main.c
+CXX_SOURCES :=
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/bitfields/main.c b/lldb/test/bitfields/main.c
new file mode 100644
index 00000000000..5edf5bdd0e0
--- /dev/null
+++ b/lldb/test/bitfields/main.c
@@ -0,0 +1,44 @@
+//===-- main.c --------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <stdint.h>
+int main (int argc, char const *argv[])
+{
+ struct Bits
+ {
+ uint32_t b1 : 1,
+ b2 : 2,
+ b3 : 3,
+ b4 : 4,
+ b5 : 5,
+ b6 : 6,
+ b7 : 7,
+ four : 4;
+ };
+
+ struct Bits bits;
+ int i;
+ for (i=0; i<(1<<1); i++)
+ bits.b1 = i; //// break $source:$line
+ for (i=0; i<(1<<2); i++)
+ bits.b2 = i; //// break $source:$line
+ for (i=0; i<(1<<3); i++)
+ bits.b3 = i; //// break $source:$line
+ for (i=0; i<(1<<4); i++)
+ bits.b4 = i; //// break $source:$line
+ for (i=0; i<(1<<5); i++)
+ bits.b5 = i; //// break $source:$line
+ for (i=0; i<(1<<6); i++)
+ bits.b6 = i; //// break $source:$line
+ for (i=0; i<(1<<7); i++)
+ bits.b7 = i; //// break $source:$line
+ for (i=0; i<(1<<4); i++)
+ bits.b4 = i; //// break $source:$line
+ return 0; //// continue
+
+}
diff --git a/lldb/test/class_types/Makefile b/lldb/test/class_types/Makefile
new file mode 100644
index 00000000000..fb5e33230e9
--- /dev/null
+++ b/lldb/test/class_types/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=
+CXX_SOURCES :=main.cpp
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/class_types/cmds.txt b/lldb/test/class_types/cmds.txt
new file mode 100644
index 00000000000..1c7ef9f1c8a
--- /dev/null
+++ b/lldb/test/class_types/cmds.txt
@@ -0,0 +1,3 @@
+b main.cpp:97
+c
+var
diff --git a/lldb/test/class_types/main.cpp b/lldb/test/class_types/main.cpp
new file mode 100644
index 00000000000..9ca8e935df9
--- /dev/null
+++ b/lldb/test/class_types/main.cpp
@@ -0,0 +1,106 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+class A
+{
+public:
+ A(int i=0):
+ m_a_int(i),
+ m_aa_int(i+1)
+ {
+ }
+
+ //virtual
+ ~A()
+ {
+ }
+
+ int
+ GetInteger() const
+ {
+ return m_a_int;
+ }
+ void
+ SetInteger(int i)
+ {
+ m_a_int = i;
+ }
+
+protected:
+ int m_a_int;
+ int m_aa_int;
+};
+
+class B : public A
+{
+public:
+ B(int ai, int bi) :
+ A(ai),
+ m_b_int(bi)
+ {
+ }
+
+ //virtual
+ ~B()
+ {
+ }
+
+ int
+ GetIntegerB() const
+ {
+ return m_b_int;
+ }
+ void
+ SetIntegerB(int i)
+ {
+ m_b_int = i;
+ }
+
+protected:
+ int m_b_int;
+};
+
+
+class C : public B
+{
+public:
+ C(int ai, int bi, int ci) :
+ B(ai, bi),
+ m_c_int(ci)
+ {
+ }
+
+ //virtual
+ ~C()
+ {
+ }
+
+ int
+ GetIntegerC() const
+ {
+ return m_c_int;
+ }
+ void
+ SetIntegerC(int i)
+ {
+ m_c_int = i;
+ }
+
+protected:
+ int m_c_int;
+};
+
+int
+main (int argc, char const *argv[])
+{
+ A a(12);
+ B b(22,33);
+ C c(44,55,66);
+ return b.GetIntegerB() - a.GetInteger() + c.GetInteger();
+}
diff --git a/lldb/test/dead-strip/Makefile b/lldb/test/dead-strip/Makefile
new file mode 100644
index 00000000000..340b46e36af
--- /dev/null
+++ b/lldb/test/dead-strip/Makefile
@@ -0,0 +1,126 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=main.c
+CXX_SOURCES :=
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS) -Xlinker -dead_strip
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+# Don't make the dSYM so we can test DWARF with debug map...
+# $(DSYM) : $(EXE)
+# $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/dead-strip/cmds.txt b/lldb/test/dead-strip/cmds.txt
new file mode 100644
index 00000000000..f6fd0450288
--- /dev/null
+++ b/lldb/test/dead-strip/cmds.txt
@@ -0,0 +1,4 @@
+b main.c:21
+b main.c:41
+lines -shlib a.out main.c
+c
diff --git a/lldb/test/dead-strip/main.c b/lldb/test/dead-strip/main.c
new file mode 100644
index 00000000000..26dfe25c694
--- /dev/null
+++ b/lldb/test/dead-strip/main.c
@@ -0,0 +1,53 @@
+//===-- main.c --------------------------------------------------*- 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>
+
+
+int f1 (char *s);
+int f2 (char *s);
+int f3 (char *s);
+
+
+// We want f1 to start on line 10
+int f1 (char *s)
+{
+ return printf("f1: %s\n", s);
+}
+
+
+
+
+
+// We want f2 to start on line 20, this should get stripped
+int f2 (char *s)
+{
+ return printf("f2: %s\n", s);
+}
+
+
+
+
+
+// We want f3 to start on line 30
+int f3 (char *s)
+{
+ return printf("f3: %s\n", s);
+}
+
+
+
+
+
+// We want main to start on line 40
+int main (int argc, const char * argv[])
+{
+ f1("carp");
+ f3("dong");
+ return 0;
+}
diff --git a/lldb/test/enum_types/Makefile b/lldb/test/enum_types/Makefile
new file mode 100644
index 00000000000..7c8745b2ab1
--- /dev/null
+++ b/lldb/test/enum_types/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=main.c
+CXX_SOURCES :=
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/enum_types/main.c b/lldb/test/enum_types/main.c
new file mode 100644
index 00000000000..1d837358ddf
--- /dev/null
+++ b/lldb/test/enum_types/main.c
@@ -0,0 +1,29 @@
+//===-- main.c --------------------------------------------------*- 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>
+
+int main (int argc, char const *argv[])
+{
+ enum days {
+ Monday = 10,
+ Tuesday,
+ Wednesday,
+ Thursday,
+ Friday,
+ Saturday,
+ Sunday,
+ kNumDays
+ };
+ enum days day;
+ for (day = Monday - 1; day <= kNumDays + 1; day++)
+ {
+ printf("day as int is %i\n", (int)day);
+ }
+ return 0;
+}
diff --git a/lldb/test/function_types/Makefile b/lldb/test/function_types/Makefile
new file mode 100644
index 00000000000..7c8745b2ab1
--- /dev/null
+++ b/lldb/test/function_types/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=main.c
+CXX_SOURCES :=
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/function_types/main.c b/lldb/test/function_types/main.c
new file mode 100644
index 00000000000..3c968e4a0e7
--- /dev/null
+++ b/lldb/test/function_types/main.c
@@ -0,0 +1,22 @@
+//===-- main.c --------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int string_not_empty (const char *s)
+{
+ if (s && s[0])
+ return 1;
+ return 0;
+}
+
+int main (int argc, char const *argv[])
+{
+ int (*callback)(const char *) = string_not_empty;
+
+ return callback(0);
+}
diff --git a/lldb/test/global_variables/Makefile b/lldb/test/global_variables/Makefile
new file mode 100644
index 00000000000..fdf381403b5
--- /dev/null
+++ b/lldb/test/global_variables/Makefile
@@ -0,0 +1,142 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=main.c
+CXX_SOURCES :=
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# dylib settings
+#----------------------------------------------------------------------
+DYLIB_NAME=a
+DYLIB_BASENAME=lib$(DYLIB_NAME).dylib
+DYLIB_C_SOURCES :=a.c
+ifneq "$(strip $(DYLIB_C_SOURCES))" ""
+ DYLIB_OBJECTS +=$(strip $(DYLIB_C_SOURCES:.c=.o))
+endif
+
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS) $(DYLIB_BASENAME)
+ $(LD) $(LDFLAGS) $(OBJECTS) -L. -l$(DYLIB_NAME) -o "$(EXE)"
+
+#----------------------------------------------------------------------
+# Make the dylib
+#----------------------------------------------------------------------
+$(DYLIB_BASENAME) : $(DYLIB_OBJECTS)
+ $(LD) $(LDFLAGS) $(DYLIB_OBJECTS) -install_name "@executable_path/$(DYLIB_BASENAME)" -dynamiclib -o "$(DYLIB_BASENAME)"
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS) $(DYLIB_OBJECTS) $(DYLIB_BASENAME) $(DYLIB_BASENAME).dSYM
+
+
+
diff --git a/lldb/test/global_variables/a.c b/lldb/test/global_variables/a.c
new file mode 100644
index 00000000000..0a9b4f61871
--- /dev/null
+++ b/lldb/test/global_variables/a.c
@@ -0,0 +1,10 @@
+//===-- a.c -----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+int g_a = 123;
+
diff --git a/lldb/test/global_variables/cmds.txt b/lldb/test/global_variables/cmds.txt
new file mode 100644
index 00000000000..6906a0729ae
--- /dev/null
+++ b/lldb/test/global_variables/cmds.txt
@@ -0,0 +1,3 @@
+break main.c:5
+continue
+var -global g_a -global g_global_int
diff --git a/lldb/test/global_variables/main.c b/lldb/test/global_variables/main.c
new file mode 100644
index 00000000000..13778c29377
--- /dev/null
+++ b/lldb/test/global_variables/main.c
@@ -0,0 +1,21 @@
+//===-- main.c --------------------------------------------------*- 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>
+
+int g_file_global_int = 42;
+const char *g_file_global_cstr = "g_file_global_cstr";
+static const char *g_file_static_cstr = "g_file_static_cstr";
+
+extern int g_a;
+int main (int argc, char const *argv[])
+{
+ static const char *g_func_static_cstr = "g_func_static_cstr";
+ printf ("%s\n", g_file_global_cstr);
+ return g_file_global_int + g_a; //// break $source:$line; continue; var -global g_a -global g_global_int
+}
diff --git a/lldb/test/load_unload/Makefile b/lldb/test/load_unload/Makefile
new file mode 100644
index 00000000000..54eb2e2ffe8
--- /dev/null
+++ b/lldb/test/load_unload/Makefile
@@ -0,0 +1,33 @@
+all: a.out liba.dylib libb.dylib libc.dylib
+
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+
+a.out: main.o
+ gcc $(CFLAGS) -o a.out main.o
+
+main.o: main.c
+ gcc $(CFLAGS) -c main.c
+
+liba.dylib: a.o libb.dylib
+ gcc $(CFLAGS) -dynamiclib -install_name "@executable_path/liba.dylib" -o liba.dylib a.o -L. -lb
+ dsymutil liba.dylib
+
+a.o: a.c
+ gcc $(CFLAGS) -c a.c
+
+libb.dylib: b.o
+ gcc $(CFLAGS) -dynamiclib -install_name "@executable_path/libb.dylib" -o libb.dylib b.o
+ dsymutil libb.dylib
+
+b.o: b.c
+ gcc $(CFLAGS) -c b.c
+
+libc.dylib: c.o
+ gcc $(CFLAGS) -dynamiclib -install_name "@executable_path/libc.dylib" -o libc.dylib c.o
+ dsymutil libc.dylib
+
+c.o: c.c
+ gcc $(CFLAGS) -c c.c
+
+clean:
+ rm -rf *.o *~ *.dylib a.out *.dSYM
diff --git a/lldb/test/load_unload/a.c b/lldb/test/load_unload/a.c
new file mode 100644
index 00000000000..9d4711772dd
--- /dev/null
+++ b/lldb/test/load_unload/a.c
@@ -0,0 +1,15 @@
+//===-- a.c -----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+extern int b_function ();
+
+int
+a_function ()
+{
+ return b_function ();
+}
diff --git a/lldb/test/load_unload/b.c b/lldb/test/load_unload/b.c
new file mode 100644
index 00000000000..6c629323655
--- /dev/null
+++ b/lldb/test/load_unload/b.c
@@ -0,0 +1,13 @@
+//===-- b.c -----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+int
+b_function ()
+{
+ return 500;
+}
diff --git a/lldb/test/load_unload/c.c b/lldb/test/load_unload/c.c
new file mode 100644
index 00000000000..b1778b462d0
--- /dev/null
+++ b/lldb/test/load_unload/c.c
@@ -0,0 +1,13 @@
+//===-- c.c -----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+int
+c_function ()
+{
+ return 600;
+}
diff --git a/lldb/test/load_unload/cmds.txt b/lldb/test/load_unload/cmds.txt
new file mode 100644
index 00000000000..1e4b198dc0d
--- /dev/null
+++ b/lldb/test/load_unload/cmds.txt
@@ -0,0 +1,2 @@
+breakpoint set -n a_function
+run
diff --git a/lldb/test/load_unload/main.c b/lldb/test/load_unload/main.c
new file mode 100644
index 00000000000..9d2882540e3
--- /dev/null
+++ b/lldb/test/load_unload/main.c
@@ -0,0 +1,72 @@
+//===-- main.c --------------------------------------------------*- 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 <dlfcn.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <stdlib.h>
+
+int
+main (int argc, char const *argv[])
+{
+ const char *a_name = "@executable_path/liba.dylib";
+ const char *c_name = "@executable_path/libc.dylib";
+ void *a_dylib_handle = NULL;
+ void *c_dylib_handle = NULL;
+ int (*a_function) (void);
+
+ a_dylib_handle = dlopen (a_name, RTLD_NOW);
+ if (a_dylib_handle == NULL)
+ {
+ fprintf (stderr, "%s\n", dlerror());
+ exit (1);
+ }
+
+ a_function = (int (*) ()) dlsym (a_dylib_handle, "a_function");
+ if (a_function == NULL)
+ {
+ fprintf (stderr, "%s\n", dlerror());
+ exit (2);
+ }
+ printf ("First time around, got: %d\n", a_function ());
+ dlclose (a_dylib_handle);
+
+ c_dylib_handle = dlopen (c_name, RTLD_NOW);
+ if (c_dylib_handle == NULL)
+ {
+ fprintf (stderr, "%s\n", dlerror());
+ exit (3);
+ }
+ a_function = (int (*) ()) dlsym (c_dylib_handle, "c_function");
+ if (a_function == NULL)
+ {
+ fprintf (stderr, "%s\n", dlerror());
+ exit (4);
+ }
+
+ a_dylib_handle = dlopen (a_name, RTLD_NOW);
+ if (a_dylib_handle == NULL)
+ {
+ fprintf (stderr, "%s\n", dlerror());
+ exit (5);
+ }
+
+ a_function = (int (*) ()) dlsym (a_dylib_handle, "a_function");
+ if (a_function == NULL)
+ {
+ fprintf (stderr, "%s\n", dlerror());
+ exit (6);
+ }
+ printf ("Second time around, got: %d\n", a_function ());
+ dlclose (a_dylib_handle);
+
+ return 0;
+}
diff --git a/lldb/test/namespace/Makefile b/lldb/test/namespace/Makefile
new file mode 100644
index 00000000000..fb5e33230e9
--- /dev/null
+++ b/lldb/test/namespace/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=
+CXX_SOURCES :=main.cpp
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/namespace/cmds.txt b/lldb/test/namespace/cmds.txt
new file mode 100644
index 00000000000..76bb1bcba75
--- /dev/null
+++ b/lldb/test/namespace/cmds.txt
@@ -0,0 +1,3 @@
+b main.cpp:54
+c
+var
diff --git a/lldb/test/namespace/main.cpp b/lldb/test/namespace/main.cpp
new file mode 100644
index 00000000000..dda8b93306b
--- /dev/null
+++ b/lldb/test/namespace/main.cpp
@@ -0,0 +1,69 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+namespace {
+ typedef unsigned int uint_t;
+ int i;
+}
+
+namespace A {
+ typedef unsigned int uint_t;
+ namespace B {
+ typedef unsigned int uint_t;
+ int j;
+ int myfunc (int a);
+ int myfunc2(int a)
+ {
+ return a + 2;
+ }
+ float myfunc (float f)
+ {
+ return f - 2.0;
+ }
+ }
+}
+
+namespace Y
+{
+ typedef unsigned int uint_t;
+ using A::B::j;
+ int foo;
+}
+
+using A::B::j; // using declaration
+
+namespace Foo = A::B; // namespace alias
+
+using Foo::myfunc; // using declaration
+
+using namespace Foo; // using directive
+
+namespace A {
+ namespace B {
+ using namespace Y;
+ int k;
+ }
+}
+
+int Foo::myfunc(int a)
+{
+ ::uint_t anon_uint = 0;
+ A::uint_t a_uint = 1;
+ B::uint_t b_uint = 2;
+ Y::uint_t y_uint = 3;
+ i = 3;
+ j = 4;
+ return myfunc2(3) + j + i + a + 2 + anon_uint + a_uint + b_uint + y_uint;
+}
+
+int
+main (int argc, char const *argv[])
+{
+ return Foo::myfunc(12);
+}
diff --git a/lldb/test/order/Makefile b/lldb/test/order/Makefile
new file mode 100644
index 00000000000..c42b4a35056
--- /dev/null
+++ b/lldb/test/order/Makefile
@@ -0,0 +1,127 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=main.c
+CXX_SOURCES :=
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS) -Xlinker -order_file ./order-file
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+# Don't make the dSYM so we can test the DWARF with debug map with
+# order files
+#$(DSYM) : $(EXE)
+# $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/order/cmds.txt b/lldb/test/order/cmds.txt
new file mode 100644
index 00000000000..8c51dd763bf
--- /dev/null
+++ b/lldb/test/order/cmds.txt
@@ -0,0 +1,3 @@
+b main.c:41
+c
+lines -shlib a.out main.c
diff --git a/lldb/test/order/main.c b/lldb/test/order/main.c
new file mode 100644
index 00000000000..1791e7c2658
--- /dev/null
+++ b/lldb/test/order/main.c
@@ -0,0 +1,54 @@
+//===-- main.c --------------------------------------------------*- 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>
+
+
+int f1 (char *s);
+int f2 (char *s);
+int f3 (char *s);
+
+
+// We want f1 to start on line 10
+int f1 (char *s)
+{
+ return printf("f1: %s\n", s);
+}
+
+
+
+
+
+// We want f2 to start on line 20
+int f2 (char *s)
+{
+ return printf("f2: %s\n", s);
+}
+
+
+
+
+
+// We want f3 to start on line 30
+int f3 (char *s)
+{
+ return printf("f3: %s\n", s);
+}
+
+
+
+
+
+// We want main to start on line 40
+int main (int argc, const char * argv[])
+{
+ f1("carp");
+ f2("ding");
+ f3("dong");
+ return 0;
+}
diff --git a/lldb/test/order/order-file b/lldb/test/order/order-file
new file mode 100644
index 00000000000..0cf8ecd2a63
--- /dev/null
+++ b/lldb/test/order/order-file
@@ -0,0 +1,4 @@
+main.o:_f3
+main.o:_main
+main.o:_f2
+main.o:_f1
diff --git a/lldb/test/print-obj/Makefile b/lldb/test/print-obj/Makefile
new file mode 100644
index 00000000000..ee9b07855d1
--- /dev/null
+++ b/lldb/test/print-obj/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=
+CXX_SOURCES :=
+OBJC_SOURCES := blocked.m
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS) -framework Foundation
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/print-obj/blocked.m b/lldb/test/print-obj/blocked.m
new file mode 100644
index 00000000000..3f5d44afead
--- /dev/null
+++ b/lldb/test/print-obj/blocked.m
@@ -0,0 +1,73 @@
+//===-- blocked.m --------------------------------------------------*- ObjC -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This file is for testing running "print object" in a case where another thread
+// blocks the print object from making progress. Set a breakpoint on the line in
+// my_pthread_routine as indicated. Then switch threads to the main thread, and
+// do print the lock_me object. Since that will try to get the lock already gotten
+// by my_pthread_routime thread, it will have to switch to running all threads, and
+// that should then succeed.
+//
+
+#include <Foundation/Foundation.h>
+#include <pthread.h>
+
+static pthread_mutex_t test_mutex;
+
+static void Mutex_Init (void)
+{
+ pthread_mutexattr_t tmp_mutex_attr;
+ pthread_mutexattr_init(&tmp_mutex_attr);
+ pthread_mutex_init(&test_mutex, &tmp_mutex_attr);
+}
+
+@interface LockMe :NSObject
+{
+
+}
+- (NSString *) description;
+@end
+
+@implementation LockMe
+- (NSString *) description
+{
+ printf ("LockMe trying to get the lock.\n");
+ pthread_mutex_lock(&test_mutex);
+ printf ("LockMe got the lock.\n");
+ pthread_mutex_unlock(&test_mutex);
+ return @"I am pretty special.\n";
+}
+@end
+
+void *
+my_pthread_routine (void *data)
+{
+ printf ("my_pthread_routine about to enter.\n");
+ pthread_mutex_lock(&test_mutex);
+ printf ("Releasing Lock.\n"); /// Set a breakpoint here.
+ pthread_mutex_unlock(&test_mutex);
+ return NULL;
+}
+
+int
+main ()
+{
+ pthread_attr_t tmp_attr;
+ pthread_attr_init (&tmp_attr);
+ pthread_t my_pthread;
+
+ Mutex_Init ();
+
+ LockMe *lock_me = [[LockMe alloc] init];
+ pthread_create (&my_pthread, &tmp_attr, my_pthread_routine, NULL);
+
+ pthread_join (my_pthread, NULL);
+
+ return 0;
+}
diff --git a/lldb/test/set_values/Makefile b/lldb/test/set_values/Makefile
new file mode 100644
index 00000000000..7c8745b2ab1
--- /dev/null
+++ b/lldb/test/set_values/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=main.c
+CXX_SOURCES :=
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/set_values/main.c b/lldb/test/set_values/main.c
new file mode 100644
index 00000000000..2a8f48d1e0b
--- /dev/null
+++ b/lldb/test/set_values/main.c
@@ -0,0 +1,116 @@
+//===-- main.c --------------------------------------------------*- 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>
+
+void set_char(void)
+{
+ char i = 'a';
+ printf("before (char) i = %c\n", i);
+ printf("after (char) i = %c\n", i); //// break $source:$line
+}
+
+void set_uchar(void)
+{
+ unsigned char i = 'a';
+ printf("before (unsigned char) i = %c\n", i);
+ printf("after (unsigned char) i = %c\n", i); //// break $source:$line
+}
+
+void set_short(void)
+{
+ short i = 33;
+ printf("before (short) i = %i\n", i);
+ printf("after (short) i = %i\n", i); //// break $source:$line
+}
+
+void set_ushort(void)
+{
+ unsigned short i = 33;
+ printf("before (unsigned short) i = %i\n", i);
+ printf("after (unsigned short) i = %i\n", i); //// break $source:$line
+}
+
+void set_int(void)
+{
+ int i = 33;
+ printf("before (int) i = %i\n", i);
+ printf("after (int) i = %i\n", i); //// break $source:$line
+}
+
+void set_uint(void)
+{
+ unsigned int i = 33;
+ printf("before (unsigned int) i = %u\n", i);
+ printf("after (unsigned int) i = %u\n", i); //// break $source:$line
+}
+
+void set_long(void)
+{
+ long i = 33;
+ printf("before (long) i = %li\n", i);
+ printf("after (long) i = %li\n", i); //// break $source:$line
+}
+
+void set_ulong(void)
+{
+ unsigned long i = 33;
+ printf("before (unsigned long) i = %lu\n", i);
+ printf("after (unsigned long) i = %lu\n", i); //// break $source:$line
+}
+
+void set_float(void)
+{
+ float i = 3.1415927;
+ printf("before (float) i = %g\n", i);
+ printf("after (float) i = %g\n", i); //// break $source:$line
+}
+
+void set_double(void)
+{
+ double i = 3.1415927;
+ printf("before (double) i = %g\n", i);
+ printf("after (double) i = %g\n", i); //// break $source:$line
+}
+
+void set_long_double(void)
+{
+ long double i = 3.1415927;
+ printf("before (long double) i = %Lg\n", i);
+ printf("after (long double) i = %Lg\n", i); //// break $source:$line
+}
+
+void set_point (void)
+{
+ struct point_tag {
+ int x;
+ int y;
+ };
+ struct point_tag points_2[2] = {
+ {1,2},
+ {3,4}
+ };
+}
+
+int main (int argc, char const *argv[])
+{
+ // Continue to the breakpoint in set_char()
+ set_char(); //// continue; var i; val -set 99 1
+ set_uchar(); //// continue; var i; val -set 99 2
+ set_short(); //// continue; var i; val -set -42 3
+ set_ushort(); //// continue; var i; val -set 42 4
+ set_int(); //// continue; var i; val -set -42 5
+ set_uint(); //// continue; var i; val -set 42 6
+ set_long(); //// continue; var i; val -set -42 7
+ set_ulong(); //// continue; var i; val -set 42 8
+ set_float(); //// continue; var i; val -set 123.456 9
+ set_double(); //// continue; var i; val -set 123.456 10
+ set_long_double(); //// continue; var i; val -set 123.456 11
+ set_point (); //// continue
+ return 0;
+}
diff --git a/lldb/test/signed_types/Makefile b/lldb/test/signed_types/Makefile
new file mode 100644
index 00000000000..fb5e33230e9
--- /dev/null
+++ b/lldb/test/signed_types/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=
+CXX_SOURCES :=main.cpp
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/signed_types/main.cpp b/lldb/test/signed_types/main.cpp
new file mode 100644
index 00000000000..fa86e7b4970
--- /dev/null
+++ b/lldb/test/signed_types/main.cpp
@@ -0,0 +1,31 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+int main (int argc, char const *argv[])
+{
+ char the_char = 'c';
+ short the_short = 'c';
+ wchar_t the_whar_t = 'c';
+ int the_int = 'c';
+ long the_long = 'c';
+ long long the_long_long = 'c';
+
+ signed char the_signed_char = 'c';
+ signed short the_signed_short = 'c';
+ signed int the_signed_int = 'c';
+ signed long the_signed_long = 'c';
+ signed long long the_signed_long_long = 'c';
+
+ return the_char - the_signed_char +
+ the_short - the_signed_short +
+ the_int - the_signed_int +
+ the_long - the_signed_long +
+ the_long_long - the_signed_long_long; //// break $source:$line; c
+ //// var the_int
+ //// val -set 22 1
+}
diff --git a/lldb/test/stl/Makefile b/lldb/test/stl/Makefile
new file mode 100644
index 00000000000..fa74214a3e1
--- /dev/null
+++ b/lldb/test/stl/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=
+CXX_SOURCES :=main.cpp
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -Os
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/stl/cmds.txt b/lldb/test/stl/cmds.txt
new file mode 100644
index 00000000000..9c9c2e3db57
--- /dev/null
+++ b/lldb/test/stl/cmds.txt
@@ -0,0 +1,3 @@
+b main.cpp:6
+continue
+var
diff --git a/lldb/test/stl/main.cpp b/lldb/test/stl/main.cpp
new file mode 100644
index 00000000000..f294b0e7500
--- /dev/null
+++ b/lldb/test/stl/main.cpp
@@ -0,0 +1,15 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <iostream>
+#include <string>
+int main (int argc, char const *argv[])
+{
+ std::string hello_world ("Hello World!");
+ std::cout << hello_world << std::endl;
+}
diff --git a/lldb/test/struct_types/Makefile b/lldb/test/struct_types/Makefile
new file mode 100644
index 00000000000..7c8745b2ab1
--- /dev/null
+++ b/lldb/test/struct_types/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=main.c
+CXX_SOURCES :=
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/struct_types/cmds.txt b/lldb/test/struct_types/cmds.txt
new file mode 100644
index 00000000000..c308a7637fb
--- /dev/null
+++ b/lldb/test/struct_types/cmds.txt
@@ -0,0 +1,3 @@
+break main.c:14
+continue
+var
diff --git a/lldb/test/struct_types/main.c b/lldb/test/struct_types/main.c
new file mode 100644
index 00000000000..0d99ee03c6f
--- /dev/null
+++ b/lldb/test/struct_types/main.c
@@ -0,0 +1,23 @@
+//===-- main.c --------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+int main (int argc, char const *argv[])
+{
+ struct point_tag {
+ int x;
+ int y;
+ };
+
+ struct rect_tag {
+ struct point_tag bottom_left;
+ struct point_tag top_right;
+ };
+ struct point_tag pt = { 2, 3 };
+ struct rect_tag rect = {{1,2}, {3,4}};
+ return 0;
+}
diff --git a/lldb/test/tester.py b/lldb/test/tester.py
new file mode 100755
index 00000000000..af2c77b0a86
--- /dev/null
+++ b/lldb/test/tester.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+# -*- coding: utf8 -*-
+
+import math, os.path, re, sys, time, unittest
+
+def setupSysPath():
+ testPath = sys.path[0]
+ rem = re.match("(^.*lldb/)test$", testPath)
+ if not rem:
+ print "This script expects to reside in .../lldb/test."
+ sys.exit(-1)
+ lldbBasePath = rem.group(1)
+ lldbDebugPythonPath = "build/Debug/LLDB.framework/Resources/Python"
+ lldbReleasePythonPath = "build/Release/LLDB.framework/Resources/Python"
+ lldbPythonPath = None
+ if os.path.isfile(lldbDebugPythonPath + "/lldb.py"):
+ lldbPythonPath = lldbDebugPythonPath
+ if os.path.isfile(lldbReleasePythonPath + "/lldb.py"):
+ lldbPythonPath = lldbReleasePythonPath
+ if not lldbPythonPath:
+ print "This script requires lldb.py to be in either " + lldbDebugPythonPath,
+ print "or" + lldbReleasePythonPath
+ sys.exit(-1)
+ sys.path.append(lldbPythonPath)
+
+def prettyTime(t):
+ if t == 0.0:
+ return "0s"
+ if t < 0.000001:
+ return ("%.3f" % (t * 1000000000.0)) + "ns"
+ if t < 0.001:
+ return ("%.3f" % (t * 1000000.0)) + "µs"
+ if t < 1:
+ return ("%.3f" % (t * 1000.0)) + "ms"
+ return str(t) + "s"
+
+class ExecutionTimes:
+ @classmethod
+ def executionTimes(cls):
+ if cls.m_executionTimes == None:
+ cls.m_executionTimes = ExecutionTimes()
+ for i in range(100):
+ cls.m_executionTimes.start()
+ cls.m_executionTimes.end("null")
+ return cls.m_executionTimes
+ def __init__(self):
+ self.m_times = dict()
+ def start(self):
+ self.m_start = time.time()
+ def end(self, component):
+ e = time.time()
+ if component not in self.m_times:
+ self.m_times[component] = list()
+ self.m_times[component].append(e - self.m_start)
+ def dumpStats(self):
+ for key in self.m_times.keys():
+ if len(self.m_times[key]):
+ sampleMin = float('inf')
+ sampleMax = float('-inf')
+ sampleSum = 0.0
+ sampleCount = 0.0
+ for time in self.m_times[key]:
+ if time > sampleMax:
+ sampleMax = time
+ if time < sampleMin:
+ sampleMin = time
+ sampleSum += time
+ sampleCount += 1.0
+ sampleMean = sampleSum / sampleCount
+ sampleVariance = 0
+ for time in self.m_times[key]:
+ sampleVariance += (time - sampleMean) ** 2
+ sampleVariance /= sampleCount
+ sampleStandardDeviation = math.sqrt(sampleVariance)
+ print key + ": [" + prettyTime(sampleMin) + ", " + prettyTime(sampleMax) + "] ",
+ print "µ " + prettyTime(sampleMean) + ", σ " + prettyTime(sampleStandardDeviation)
+ m_executionTimes = None
+
+setupSysPath()
+
+import lldb
+
+class LLDBTestCase(unittest.TestCase):
+ def setUp(self):
+ lldb.SBDebugger.SetAsync(True)
+ self.m_commandInterpreter = lldb.SBDebugger.GetCommandInterpreter()
+ if not self.m_commandInterpreter:
+ print "Couldn't get the command interpreter"
+ sys.exit(-1)
+ def runCommand(self, command, component):
+ res = lldb.SBCommandReturnObject()
+ ExecutionTimes.executionTimes().start()
+ self.m_commandInterpreter.HandleCommand(command, res, False)
+ ExecutionTimes.executionTimes().end(component)
+ if res.Succeeded():
+ return res.GetOutput()
+ else:
+ self.fail("Command " + command + " returned an error")
+ return None
+
+class SanityCheckTestCase(LLDBTestCase):
+ def runTest(self):
+ ret = self.runCommand("show arch", "show-arch")
+
+suite = unittest.TestLoader().loadTestsFromTestCase(SanityCheckTestCase)
+unittest.TextTestRunner(verbosity=2).run(suite)
+ExecutionTimes.executionTimes().dumpStats()
diff --git a/lldb/test/threads/Makefile b/lldb/test/threads/Makefile
new file mode 100644
index 00000000000..fb5e33230e9
--- /dev/null
+++ b/lldb/test/threads/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=
+CXX_SOURCES :=main.cpp
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/threads/main.cpp b/lldb/test/threads/main.cpp
new file mode 100644
index 00000000000..dddf0087ed2
--- /dev/null
+++ b/lldb/test/threads/main.cpp
@@ -0,0 +1,129 @@
+//===-- main.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 <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+using namespace std;
+
+pthread_t g_thread_1 = NULL;
+pthread_t g_thread_2 = NULL;
+pthread_t g_thread_3 = NULL;
+
+typedef enum {
+ eGet,
+ eAssign,
+ eClearBits
+} MaskAction;
+
+uint32_t mask_access (MaskAction action, uint32_t mask = 0);
+
+uint32_t
+mask_access (MaskAction action, uint32_t mask)
+{
+ static pthread_mutex_t g_mask_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static uint32_t g_mask = 0;
+ ::pthread_mutex_lock (&g_mask_mutex);
+ switch (action)
+ {
+ case eGet:
+ break;
+
+ case eAssign:
+ g_mask |= mask;
+ break;
+
+ case eClearBits:
+ g_mask &= ~mask;
+ break;
+ }
+ uint32_t new_mask = g_mask;
+ ::pthread_mutex_unlock (&g_mask_mutex);
+ return new_mask;
+}
+
+void *
+thread_func (void *arg)
+{
+ uint32_t thread_index = *((uint32_t *)arg);
+ uint32_t thread_mask = (1u << (thread_index));
+ printf ("%s (thread index = %u) startng...\n", __FUNCTION__, thread_index);
+
+ while (mask_access(eGet) & thread_mask)
+ {
+ // random micro second sleep from zero to 3 seconds
+ long usec = ::random() % 3000000;
+ printf ("%s (thread = %u) doing a usleep (%li)...\n", __FUNCTION__, thread_index, usec);
+ ::usleep (usec);
+ }
+ printf ("%s (thread index = %u) exiting...\n", __FUNCTION__, thread_index);
+
+}
+
+
+int main (int argc, char const *argv[])
+{
+ int err;
+ void *thread_result = NULL;
+ uint32_t thread_index_1 = 1;
+ uint32_t thread_index_2 = 2;
+ uint32_t thread_index_3 = 3;
+ uint32_t thread_mask_1 = (1u << thread_index_1);
+ uint32_t thread_mask_2 = (1u << thread_index_2);
+ uint32_t thread_mask_3 = (1u << thread_index_3);
+
+ // Make a mask that will keep all threads alive
+ mask_access (eAssign, thread_mask_1 | thread_mask_2 | thread_mask_3);
+
+ // Create 3 threads
+ err = ::pthread_create (&g_thread_1, NULL, thread_func, &thread_index_1);
+ err = ::pthread_create (&g_thread_2, NULL, thread_func, &thread_index_2);
+ err = ::pthread_create (&g_thread_3, NULL, thread_func, &thread_index_3);
+
+ char line[64];
+ while (mask_access(eGet) != 0)
+ {
+ printf ("Enter thread index to kill or ENTER for all:\n");
+ fflush (stdout);
+ // Kill threads by index, or ENTER for all threads
+
+ if (fgets (line, sizeof(line), stdin))
+ {
+ if (line[0] == '\n' || line[0] == '\r' || line[0] == '\0')
+ {
+ printf ("Exiting all threads...\n");
+ break;
+ }
+ int32_t index = strtoul (line, NULL, 0);
+ switch (index)
+ {
+ case 1: mask_access (eClearBits, thread_mask_1); break;
+ case 2: mask_access (eClearBits, thread_mask_2); break;
+ case 3: mask_access (eClearBits, thread_mask_3); break;
+ }
+ continue;
+ }
+
+ break;
+ }
+
+ // Clear all thread bits to they all exit
+ mask_access (eClearBits, UINT32_MAX);
+
+ // Join all of our threads
+ err = ::pthread_join (g_thread_1, &thread_result);
+ err = ::pthread_join (g_thread_2, &thread_result);
+ err = ::pthread_join (g_thread_3, &thread_result);
+
+ return 0;
+} \ No newline at end of file
diff --git a/lldb/test/unsigned_types/Makefile b/lldb/test/unsigned_types/Makefile
new file mode 100644
index 00000000000..fb5e33230e9
--- /dev/null
+++ b/lldb/test/unsigned_types/Makefile
@@ -0,0 +1,125 @@
+#----------------------------------------------------------------------
+# Fill in the source files to build
+#----------------------------------------------------------------------
+C_SOURCES :=
+CXX_SOURCES :=main.cpp
+OBJC_SOURCES :=
+OBJCXX_SOURCES :=
+
+# Uncomment line below for debugging shell commands
+# SHELL = /bin/sh -x
+
+#----------------------------------------------------------------------
+# Change any build/tool options needed
+#----------------------------------------------------------------------
+DS := /usr/bin/dsymutil
+DSFLAGS =
+CFLAGS ?=-arch x86_64 -gdwarf-2 -O0
+CPLUSPLUSFLAGS +=$(CFLAGS)
+CPPFLAGS +=$(CFLAGS)
+LD = gcc
+LDFLAGS = $(CFLAGS)
+OBJECTS =
+EXE=a.out
+DSYM=$(EXE).dSYM
+
+#----------------------------------------------------------------------
+# Check if we have any C source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(C_SOURCES))" ""
+ OBJECTS +=$(strip $(C_SOURCES:.c=.o))
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any C++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(CXX_SOURCES))" ""
+ OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o))
+ LD = g++
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJC_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o))
+ LDFLAGS +=-lobjc
+endif
+
+#----------------------------------------------------------------------
+# Check if we have any ObjC++ source files
+#----------------------------------------------------------------------
+ifneq "$(strip $(OBJCXX_SOURCES))" ""
+ OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o))
+ LD = g++
+ ifeq $(findstring lobjc,$(LDFLAGS)) ""
+ LDFLAGS +=-lobjc
+ endif
+endif
+
+
+#----------------------------------------------------------------------
+# Make the dSYM file from the executable
+#----------------------------------------------------------------------
+$(DSYM) : $(EXE)
+ $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)"
+
+#----------------------------------------------------------------------
+# Compile the executable from all the objects (default rule) with no
+# dsym file.
+#----------------------------------------------------------------------
+$(EXE) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)"
+
+
+#----------------------------------------------------------------------
+# Automatic variables based on items already entered. Below we create
+# an objects lists from the list of sources by replacing all entries
+# that end with .c with .o, and we also create a list of prerequisite
+# files by replacing all .c files with .d.
+#----------------------------------------------------------------------
+PREREQS := $(OBJECTS:.o=.d)
+
+#----------------------------------------------------------------------
+# Rule for Generating Prerequisites Automatically using .d files and
+# the compiler -MM option. The -M option will list all system headers,
+# and the -MM option will list all non-system dependencies.
+#----------------------------------------------------------------------
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.cpp
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.m
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+%.d: %.mm
+ @set -e; rm -f $@; \
+ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
+
+#----------------------------------------------------------------------
+# Include all of the makefiles for each source file so we don't have
+# to manually track all of the prerequisites for each source file.
+#----------------------------------------------------------------------
+sinclude $(PREREQS)
+
+.PHONY: clean
+dsym: $(DSYM)
+all: $(EXE) $(DSYM)
+clean:
+ rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS)
+
+
+
diff --git a/lldb/test/unsigned_types/main.cpp b/lldb/test/unsigned_types/main.cpp
new file mode 100644
index 00000000000..c18d85a74e7
--- /dev/null
+++ b/lldb/test/unsigned_types/main.cpp
@@ -0,0 +1,22 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+int main (int argc, char const *argv[])
+{
+ typedef unsigned int uint32_t;
+ unsigned char the_unsigned_char = 'c';
+ unsigned short the_unsigned_short = 'c';
+ unsigned int the_unsigned_int = 'c';
+ unsigned long the_unsigned_long = 'c';
+ unsigned long long the_unsigned_long_long = 'c';
+ uint32_t the_uint32 = 'c';
+
+ return the_unsigned_char - the_unsigned_short +
+ the_unsigned_int - the_unsigned_long +
+ the_unsigned_long_long - the_uint32;
+}
diff --git a/lldb/tools/debugserver/debugnub-exports b/lldb/tools/debugserver/debugnub-exports
new file mode 100644
index 00000000000..662bf9308a6
--- /dev/null
+++ b/lldb/tools/debugserver/debugnub-exports
@@ -0,0 +1,2 @@
+_DNB*
+__DNB*
diff --git a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj
new file mode 100644
index 00000000000..14f84acc9f9
--- /dev/null
+++ b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj
@@ -0,0 +1,604 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 2660D9CE1192280900958FBD /* StringExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2660D9CC1192280900958FBD /* StringExtractor.cpp */; };
+ 26CE05A7115C360D0022F371 /* DNBError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DE0C71334A0024798E /* DNBError.cpp */; };
+ 26CE05A8115C36170022F371 /* DNBThreadResumeActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */; };
+ 26CE05A9115C36250022F371 /* debugserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A02918114AB9240029C479 /* debugserver.cpp */; };
+ 26CE05AA115C36260022F371 /* RNBContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68F7E0D104EC800665A9E /* RNBContext.cpp */; };
+ 26CE05AB115C36270022F371 /* RNBServices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF8878A00D9C797C001831DA /* RNBServices.cpp */; };
+ 26CE05AC115C36280022F371 /* RNBSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */; };
+ 26CE05AD115C36280022F371 /* RNBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FD60D10574500665A9E /* RNBRemote.cpp */; };
+ 26CE05AE115C36320022F371 /* dbgnub-mig.defs in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E80C71334A0024798E /* dbgnub-mig.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
+ 26CE05B0115C36340022F371 /* MachException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EE0C71334A0024798E /* MachException.cpp */; };
+ 26CE05B1115C36350022F371 /* MachProcess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F00C71334A0024798E /* MachProcess.cpp */; };
+ 26CE05B2115C36360022F371 /* MachThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F20C71334A0024798E /* MachThread.cpp */; };
+ 26CE05B3115C36370022F371 /* MachThreadList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F40C71334A0024798E /* MachThreadList.cpp */; };
+ 26CE05B4115C36380022F371 /* MachVMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F60C71334A0024798E /* MachVMMemory.cpp */; };
+ 26CE05B5115C36380022F371 /* MachVMRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F80C71334A0024798E /* MachVMRegion.cpp */; };
+ 26CE05B6115C36390022F371 /* MachTask.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26B67DE10EE9BC30006C8BC0 /* MachTask.cpp */; };
+ 26CE05B7115C363B0022F371 /* DNB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D60C71334A0024798E /* DNB.cpp */; };
+ 26CE05B8115C363C0022F371 /* DNBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */; };
+ 26CE05B9115C363D0022F371 /* DNBDataRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DB0C71334A0024798E /* DNBDataRef.cpp */; };
+ 26CE05BA115C363E0022F371 /* DNBLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E00C71334A0024798E /* DNBLog.cpp */; };
+ 26CE05BB115C363F0022F371 /* DNBRegisterInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */; };
+ 26CE05BC115C36420022F371 /* PThreadEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637FE0C71334A0024798E /* PThreadEvent.cpp */; };
+ 26CE05BD115C36430022F371 /* PThreadMutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */; };
+ 26CE05BE115C36440022F371 /* SysSignal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C638010C71334A0024798E /* SysSignal.cpp */; };
+ 26CE05BF115C364D0022F371 /* DNBArchImplX86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */; };
+ 26CE05C0115C364F0022F371 /* DNBArchImplI386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */; };
+ 26CE05C1115C36510022F371 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */; };
+ 26CE05C2115C36550022F371 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637FB0C71334A0024798E /* DNBArchImpl.cpp */; };
+ 26CE05C3115C36580022F371 /* CFString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */; };
+ 26CE05C4115C36590022F371 /* CFData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DE2E0D3EE55B007E4CA2 /* CFData.cpp */; };
+ 26CE05C5115C36590022F371 /* CFBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */; };
+ 26CE05CF115C36F70022F371 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26ACA3340D3E956300A2120B /* CoreFoundation.framework */; };
+ 26CE05F1115C387C0022F371 /* PseudoTerminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 260828DE0CBAF7F400F95054 /* DNBRuntimeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBRuntimeAction.h; sourceTree = "<group>"; };
+ 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBThreadResumeActions.cpp; sourceTree = "<group>"; };
+ 260E7332114BFFE600D1DFB3 /* DNBThreadResumeActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBThreadResumeActions.h; sourceTree = "<group>"; };
+ 260FC7320E5B290400043FC9 /* debugnub-exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "debugnub-exports"; sourceTree = SOURCE_ROOT; };
+ 26242C390DDBD33C0054A4CC /* debugserver-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "debugserver-entitlements.plist"; sourceTree = "<group>"; };
+ 26593A060D4931CC001C9FE3 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; };
+ 2660D9CC1192280900958FBD /* StringExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringExtractor.cpp; path = ../../source/Utility/StringExtractor.cpp; sourceTree = SOURCE_ROOT; };
+ 2660D9CD1192280900958FBD /* StringExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringExtractor.h; path = ../../source/Utility/StringExtractor.h; sourceTree = SOURCE_ROOT; };
+ 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PThreadMutex.cpp; sourceTree = "<group>"; };
+ 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DNBArchImpl.cpp; path = arm/DNBArchImpl.cpp; sourceTree = "<group>"; };
+ 2675D4230CCEB705000F49AF /* DNBArchImpl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DNBArchImpl.h; path = arm/DNBArchImpl.h; sourceTree = "<group>"; };
+ 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CFBundle.cpp; sourceTree = "<group>"; };
+ 2695DD920D3EBFF6007E4CA2 /* CFBundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFBundle.h; sourceTree = "<group>"; };
+ 2695DD9A0D3EC160007E4CA2 /* CFString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFString.h; sourceTree = "<group>"; };
+ 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CFString.cpp; sourceTree = "<group>"; };
+ 2695DE2D0D3EE55B007E4CA2 /* CFData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFData.h; sourceTree = "<group>"; };
+ 2695DE2E0D3EE55B007E4CA2 /* CFData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CFData.cpp; sourceTree = "<group>"; };
+ 269DE5C50CB5B723008989F0 /* ProfileObjectiveC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProfileObjectiveC.h; sourceTree = "<group>"; };
+ 269DE5C60CB5B723008989F0 /* ProfileObjectiveC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProfileObjectiveC.cpp; sourceTree = "<group>"; };
+ 26A02918114AB9240029C479 /* debugserver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debugserver.cpp; sourceTree = "<group>"; };
+ 26A4BAED0D498B7D00A9BEAB /* com.apple.debugserver.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.plist; sourceTree = "<group>"; };
+ 26A68F7D0D104EC800665A9E /* RNBContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBContext.h; sourceTree = "<group>"; };
+ 26A68F7E0D104EC800665A9E /* RNBContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBContext.cpp; sourceTree = "<group>"; };
+ 26A68FAF0D1054DA00665A9E /* RNBSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBSocket.h; sourceTree = "<group>"; };
+ 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBSocket.cpp; sourceTree = "<group>"; };
+ 26A68FD50D10574500665A9E /* RNBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBRemote.h; sourceTree = "<group>"; };
+ 26A68FD60D10574500665A9E /* RNBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBRemote.cpp; sourceTree = "<group>"; };
+ 26A8FE1E0D11A77B00203048 /* DNBTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBTimer.h; sourceTree = "<group>"; };
+ 26A901EA0EA3F46B00F7C71E /* FunctionProfiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionProfiler.cpp; sourceTree = "<group>"; };
+ 26A901EB0EA3F46B00F7C71E /* FunctionProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctionProfiler.h; sourceTree = "<group>"; };
+ 26ACA3340D3E956300A2120B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+ 26B67DE00EE9BC30006C8BC0 /* MachTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachTask.h; sourceTree = "<group>"; };
+ 26B67DE10EE9BC30006C8BC0 /* MachTask.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachTask.cpp; sourceTree = "<group>"; };
+ 26C636AD0C71303A0024798E /* dbgnub-config.pl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = "dbgnub-config.pl"; sourceTree = "<group>"; };
+ 26C637D60C71334A0024798E /* DNB.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNB.cpp; sourceTree = "<group>"; };
+ 26C637D70C71334A0024798E /* DNB.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNB.h; sourceTree = "<group>"; };
+ 26C637D80C71334A0024798E /* DNBArch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArch.h; sourceTree = "<group>"; };
+ 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBBreakpoint.cpp; sourceTree = "<group>"; };
+ 26C637DA0C71334A0024798E /* DNBBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBBreakpoint.h; sourceTree = "<group>"; };
+ 26C637DB0C71334A0024798E /* DNBDataRef.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBDataRef.cpp; sourceTree = "<group>"; };
+ 26C637DC0C71334A0024798E /* DNBDataRef.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBDataRef.h; sourceTree = "<group>"; };
+ 26C637DD0C71334A0024798E /* DNBDefs.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBDefs.h; sourceTree = "<group>"; };
+ 26C637DE0C71334A0024798E /* DNBError.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBError.cpp; sourceTree = "<group>"; };
+ 26C637DF0C71334A0024798E /* DNBError.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBError.h; sourceTree = "<group>"; };
+ 26C637E00C71334A0024798E /* DNBLog.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBLog.cpp; sourceTree = "<group>"; };
+ 26C637E10C71334A0024798E /* DNBLog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBLog.h; sourceTree = "<group>"; };
+ 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBRegisterInfo.cpp; sourceTree = "<group>"; };
+ 26C637E30C71334A0024798E /* DNBRegisterInfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBRegisterInfo.h; sourceTree = "<group>"; };
+ 26C637E70C71334A0024798E /* CFUtils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CFUtils.h; sourceTree = "<group>"; };
+ 26C637E80C71334A0024798E /* dbgnub-mig.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 30; path = "dbgnub-mig.defs"; sourceTree = "<group>"; };
+ 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplI386.cpp; sourceTree = "<group>"; };
+ 26C637EB0C71334A0024798E /* DNBArchImplI386.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArchImplI386.h; sourceTree = "<group>"; };
+ 26C637EC0C71334A0024798E /* MachDYLD.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachDYLD.cpp; sourceTree = "<group>"; };
+ 26C637ED0C71334A0024798E /* MachDYLD.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachDYLD.h; sourceTree = "<group>"; };
+ 26C637EE0C71334A0024798E /* MachException.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachException.cpp; sourceTree = "<group>"; };
+ 26C637EF0C71334A0024798E /* MachException.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachException.h; sourceTree = "<group>"; };
+ 26C637F00C71334A0024798E /* MachProcess.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachProcess.cpp; sourceTree = "<group>"; };
+ 26C637F10C71334A0024798E /* MachProcess.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachProcess.h; sourceTree = "<group>"; };
+ 26C637F20C71334A0024798E /* MachThread.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachThread.cpp; sourceTree = "<group>"; };
+ 26C637F30C71334A0024798E /* MachThread.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachThread.h; sourceTree = "<group>"; };
+ 26C637F40C71334A0024798E /* MachThreadList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachThreadList.cpp; sourceTree = "<group>"; };
+ 26C637F50C71334A0024798E /* MachThreadList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachThreadList.h; sourceTree = "<group>"; };
+ 26C637F60C71334A0024798E /* MachVMMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachVMMemory.cpp; sourceTree = "<group>"; };
+ 26C637F70C71334A0024798E /* MachVMMemory.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachVMMemory.h; sourceTree = "<group>"; };
+ 26C637F80C71334A0024798E /* MachVMRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachVMRegion.cpp; sourceTree = "<group>"; };
+ 26C637F90C71334A0024798E /* MachVMRegion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachVMRegion.h; sourceTree = "<group>"; };
+ 26C637FB0C71334A0024798E /* DNBArchImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImpl.cpp; sourceTree = "<group>"; };
+ 26C637FC0C71334A0024798E /* DNBArchImpl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArchImpl.h; sourceTree = "<group>"; };
+ 26C637FD0C71334A0024798E /* PThreadCondition.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PThreadCondition.h; sourceTree = "<group>"; };
+ 26C637FE0C71334A0024798E /* PThreadEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PThreadEvent.cpp; sourceTree = "<group>"; };
+ 26C637FF0C71334A0024798E /* PThreadEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PThreadEvent.h; sourceTree = "<group>"; };
+ 26C638000C71334A0024798E /* PThreadMutex.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PThreadMutex.h; sourceTree = "<group>"; };
+ 26C638010C71334A0024798E /* SysSignal.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SysSignal.cpp; sourceTree = "<group>"; };
+ 26C638020C71334A0024798E /* SysSignal.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SysSignal.h; sourceTree = "<group>"; };
+ 26C638050C71334A0024798E /* TTYState.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TTYState.cpp; sourceTree = "<group>"; };
+ 26C638060C71334A0024798E /* TTYState.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = TTYState.h; sourceTree = "<group>"; };
+ 26CE0594115C31C20022F371 /* debugserver */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = debugserver; sourceTree = BUILT_PRODUCTS_DIR; };
+ 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplX86_64.cpp; sourceTree = "<group>"; };
+ 26CF99A31142EB7400011AAB /* DNBArchImplX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBArchImplX86_64.h; sourceTree = "<group>"; };
+ 26E6B9DA0D1329010037ECDD /* RNBDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBDefs.h; sourceTree = "<group>"; };
+ AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PseudoTerminal.cpp; sourceTree = "<group>"; };
+ AF67AC000D34604D0022D128 /* PseudoTerminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PseudoTerminal.h; sourceTree = "<group>"; };
+ EF88788B0D9C7558001831DA /* com.apple.debugserver.applist.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.applist.plist; sourceTree = "<group>"; };
+ EF88789F0D9C797C001831DA /* RNBServices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBServices.h; sourceTree = "<group>"; };
+ EF8878A00D9C797C001831DA /* RNBServices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBServices.cpp; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 26CE0592115C31C20022F371 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 26CE05CF115C36F70022F371 /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* dbgnub */ = {
+ isa = PBXGroup;
+ children = (
+ 26ACA3330D3E94F200A2120B /* Framework */,
+ 26C637D50C71334A0024798E /* source */,
+ 26C636AC0C71303A0024798E /* scripts */,
+ 1AB674ADFE9D54B511CA2CBB /* Products */,
+ );
+ name = dbgnub;
+ sourceTree = "<group>";
+ };
+ 1AB674ADFE9D54B511CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 26CE0594115C31C20022F371 /* debugserver */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 2675D41C0CCEB6CF000F49AF /* arm */ = {
+ isa = PBXGroup;
+ children = (
+ 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */,
+ 2675D4230CCEB705000F49AF /* DNBArchImpl.h */,
+ );
+ name = arm;
+ sourceTree = "<group>";
+ };
+ 26A028FE114AB6A60029C479 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 260FC7320E5B290400043FC9 /* debugnub-exports */,
+ 26242C390DDBD33C0054A4CC /* debugserver-entitlements.plist */,
+ 26A4BAED0D498B7D00A9BEAB /* com.apple.debugserver.plist */,
+ EF88788B0D9C7558001831DA /* com.apple.debugserver.applist.plist */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 26A028FF114AB6BB0029C479 /* libdebugnub */ = {
+ isa = PBXGroup;
+ children = (
+ 26C637E60C71334A0024798E /* MacOSX */,
+ 260828DE0CBAF7F400F95054 /* DNBRuntimeAction.h */,
+ 26A8FE1E0D11A77B00203048 /* DNBTimer.h */,
+ 26C637D70C71334A0024798E /* DNB.h */,
+ 26C637D60C71334A0024798E /* DNB.cpp */,
+ 26C637D80C71334A0024798E /* DNBArch.h */,
+ 26C637DA0C71334A0024798E /* DNBBreakpoint.h */,
+ 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */,
+ 26C637DC0C71334A0024798E /* DNBDataRef.h */,
+ 26C637DB0C71334A0024798E /* DNBDataRef.cpp */,
+ 26C637DD0C71334A0024798E /* DNBDefs.h */,
+ 26C637DF0C71334A0024798E /* DNBError.h */,
+ 26C637DE0C71334A0024798E /* DNBError.cpp */,
+ 26C637E10C71334A0024798E /* DNBLog.h */,
+ 26C637E00C71334A0024798E /* DNBLog.cpp */,
+ 26C637E30C71334A0024798E /* DNBRegisterInfo.h */,
+ 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */,
+ 260E7332114BFFE600D1DFB3 /* DNBThreadResumeActions.h */,
+ 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */,
+ AF67AC000D34604D0022D128 /* PseudoTerminal.h */,
+ AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */,
+ 26C637FD0C71334A0024798E /* PThreadCondition.h */,
+ 26C637FF0C71334A0024798E /* PThreadEvent.h */,
+ 26C637FE0C71334A0024798E /* PThreadEvent.cpp */,
+ 26C638000C71334A0024798E /* PThreadMutex.h */,
+ 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */,
+ 26C638020C71334A0024798E /* SysSignal.h */,
+ 26C638010C71334A0024798E /* SysSignal.cpp */,
+ 26C638060C71334A0024798E /* TTYState.h */,
+ 26C638050C71334A0024798E /* TTYState.cpp */,
+ );
+ name = libdebugnub;
+ sourceTree = "<group>";
+ };
+ 26A02900114AB6DB0029C479 /* Utility */ = {
+ isa = PBXGroup;
+ children = (
+ 26A901EB0EA3F46B00F7C71E /* FunctionProfiler.h */,
+ 26A901EA0EA3F46B00F7C71E /* FunctionProfiler.cpp */,
+ 269DE5C50CB5B723008989F0 /* ProfileObjectiveC.h */,
+ 269DE5C60CB5B723008989F0 /* ProfileObjectiveC.cpp */,
+ );
+ name = Utility;
+ sourceTree = "<group>";
+ };
+ 26ACA3330D3E94F200A2120B /* Framework */ = {
+ isa = PBXGroup;
+ children = (
+ 26ACA3340D3E956300A2120B /* CoreFoundation.framework */,
+ );
+ name = Framework;
+ sourceTree = "<group>";
+ };
+ 26C636AC0C71303A0024798E /* scripts */ = {
+ isa = PBXGroup;
+ children = (
+ 26C636AD0C71303A0024798E /* dbgnub-config.pl */,
+ );
+ path = scripts;
+ sourceTree = "<group>";
+ };
+ 26C637D50C71334A0024798E /* source */ = {
+ isa = PBXGroup;
+ children = (
+ 26593A060D4931CC001C9FE3 /* ChangeLog */,
+ 26DEFD6C0D104C23008A5A07 /* debugserver */,
+ 26A028FF114AB6BB0029C479 /* libdebugnub */,
+ 26A02900114AB6DB0029C479 /* Utility */,
+ );
+ indentWidth = 4;
+ path = source;
+ sourceTree = "<group>";
+ tabWidth = 4;
+ usesTabs = 0;
+ };
+ 26C637E60C71334A0024798E /* MacOSX */ = {
+ isa = PBXGroup;
+ children = (
+ 2695DD920D3EBFF6007E4CA2 /* CFBundle.h */,
+ 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */,
+ 2695DE2D0D3EE55B007E4CA2 /* CFData.h */,
+ 2695DE2E0D3EE55B007E4CA2 /* CFData.cpp */,
+ 2695DD9A0D3EC160007E4CA2 /* CFString.h */,
+ 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */,
+ 26C637E70C71334A0024798E /* CFUtils.h */,
+ 2675D41C0CCEB6CF000F49AF /* arm */,
+ 26C637E90C71334A0024798E /* i386 */,
+ 26C637FA0C71334A0024798E /* ppc */,
+ 26CF99A11142EB7400011AAB /* x86_64 */,
+ 26C637E80C71334A0024798E /* dbgnub-mig.defs */,
+ 26C637ED0C71334A0024798E /* MachDYLD.h */,
+ 26C637EC0C71334A0024798E /* MachDYLD.cpp */,
+ 26C637EF0C71334A0024798E /* MachException.h */,
+ 26C637EE0C71334A0024798E /* MachException.cpp */,
+ 26C637F10C71334A0024798E /* MachProcess.h */,
+ 26C637F00C71334A0024798E /* MachProcess.cpp */,
+ 26C637F30C71334A0024798E /* MachThread.h */,
+ 26C637F20C71334A0024798E /* MachThread.cpp */,
+ 26C637F50C71334A0024798E /* MachThreadList.h */,
+ 26C637F40C71334A0024798E /* MachThreadList.cpp */,
+ 26C637F70C71334A0024798E /* MachVMMemory.h */,
+ 26C637F60C71334A0024798E /* MachVMMemory.cpp */,
+ 26C637F90C71334A0024798E /* MachVMRegion.h */,
+ 26C637F80C71334A0024798E /* MachVMRegion.cpp */,
+ 26B67DE00EE9BC30006C8BC0 /* MachTask.h */,
+ 26B67DE10EE9BC30006C8BC0 /* MachTask.cpp */,
+ );
+ path = MacOSX;
+ sourceTree = "<group>";
+ };
+ 26C637E90C71334A0024798E /* i386 */ = {
+ isa = PBXGroup;
+ children = (
+ 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */,
+ 26C637EB0C71334A0024798E /* DNBArchImplI386.h */,
+ );
+ path = i386;
+ sourceTree = "<group>";
+ };
+ 26C637FA0C71334A0024798E /* ppc */ = {
+ isa = PBXGroup;
+ children = (
+ 26C637FB0C71334A0024798E /* DNBArchImpl.cpp */,
+ 26C637FC0C71334A0024798E /* DNBArchImpl.h */,
+ );
+ path = ppc;
+ sourceTree = "<group>";
+ };
+ 26CF99A11142EB7400011AAB /* x86_64 */ = {
+ isa = PBXGroup;
+ children = (
+ 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */,
+ 26CF99A31142EB7400011AAB /* DNBArchImplX86_64.h */,
+ );
+ path = x86_64;
+ sourceTree = "<group>";
+ };
+ 26DEFD6C0D104C23008A5A07 /* debugserver */ = {
+ isa = PBXGroup;
+ children = (
+ 26A02918114AB9240029C479 /* debugserver.cpp */,
+ 26A028FE114AB6A60029C479 /* Resources */,
+ 26A68F7D0D104EC800665A9E /* RNBContext.h */,
+ 26A68F7E0D104EC800665A9E /* RNBContext.cpp */,
+ EF88789F0D9C797C001831DA /* RNBServices.h */,
+ EF8878A00D9C797C001831DA /* RNBServices.cpp */,
+ 26A68FAF0D1054DA00665A9E /* RNBSocket.h */,
+ 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */,
+ 26A68FD50D10574500665A9E /* RNBRemote.h */,
+ 26A68FD60D10574500665A9E /* RNBRemote.cpp */,
+ 26E6B9DA0D1329010037ECDD /* RNBDefs.h */,
+ 2660D9CD1192280900958FBD /* StringExtractor.h */,
+ 2660D9CC1192280900958FBD /* StringExtractor.cpp */,
+ );
+ name = debugserver;
+ sourceTree = "<group>";
+ usesTabs = 0;
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 26CE0593115C31C20022F371 /* debugserver */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 26CE05A4115C31ED0022F371 /* Build configuration list for PBXNativeTarget "debugserver" */;
+ buildPhases = (
+ 26CE05C7115C36870022F371 /* ShellScript */,
+ 26CE0591115C31C20022F371 /* Sources */,
+ 26CE0592115C31C20022F371 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = debugserver;
+ productName = "lldb-debugserver";
+ productReference = 26CE0594115C31C20022F371 /* debugserver */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "debugserver" */;
+ compatibilityVersion = "Xcode 3.1";
+ hasScannedForEncodings = 1;
+ mainGroup = 08FB7794FE84155DC02AAC07 /* dbgnub */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 26CE0593115C31C20022F371 /* debugserver */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 26CE05C7115C36870022F371 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/scripts/dbgnub-config.pl",
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/DNBConfig.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "perl -x scripts/dbgnub-config.pl\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 26CE0591115C31C20022F371 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 26CE05A7115C360D0022F371 /* DNBError.cpp in Sources */,
+ 26CE05A8115C36170022F371 /* DNBThreadResumeActions.cpp in Sources */,
+ 26CE05A9115C36250022F371 /* debugserver.cpp in Sources */,
+ 26CE05AA115C36260022F371 /* RNBContext.cpp in Sources */,
+ 26CE05AB115C36270022F371 /* RNBServices.cpp in Sources */,
+ 26CE05AC115C36280022F371 /* RNBSocket.cpp in Sources */,
+ 26CE05AD115C36280022F371 /* RNBRemote.cpp in Sources */,
+ 26CE05AE115C36320022F371 /* dbgnub-mig.defs in Sources */,
+ 26CE05B0115C36340022F371 /* MachException.cpp in Sources */,
+ 26CE05B1115C36350022F371 /* MachProcess.cpp in Sources */,
+ 26CE05B2115C36360022F371 /* MachThread.cpp in Sources */,
+ 26CE05B3115C36370022F371 /* MachThreadList.cpp in Sources */,
+ 26CE05B4115C36380022F371 /* MachVMMemory.cpp in Sources */,
+ 26CE05B5115C36380022F371 /* MachVMRegion.cpp in Sources */,
+ 26CE05B6115C36390022F371 /* MachTask.cpp in Sources */,
+ 26CE05B7115C363B0022F371 /* DNB.cpp in Sources */,
+ 26CE05B8115C363C0022F371 /* DNBBreakpoint.cpp in Sources */,
+ 26CE05B9115C363D0022F371 /* DNBDataRef.cpp in Sources */,
+ 26CE05BA115C363E0022F371 /* DNBLog.cpp in Sources */,
+ 26CE05BB115C363F0022F371 /* DNBRegisterInfo.cpp in Sources */,
+ 26CE05BC115C36420022F371 /* PThreadEvent.cpp in Sources */,
+ 26CE05BD115C36430022F371 /* PThreadMutex.cpp in Sources */,
+ 26CE05BE115C36440022F371 /* SysSignal.cpp in Sources */,
+ 26CE05BF115C364D0022F371 /* DNBArchImplX86_64.cpp in Sources */,
+ 26CE05C0115C364F0022F371 /* DNBArchImplI386.cpp in Sources */,
+ 26CE05C1115C36510022F371 /* DNBArchImpl.cpp in Sources */,
+ 26CE05C2115C36550022F371 /* DNBArchImpl.cpp in Sources */,
+ 26CE05C3115C36580022F371 /* CFString.cpp in Sources */,
+ 26CE05C4115C36590022F371 /* CFData.cpp in Sources */,
+ 26CE05C5115C36590022F371 /* CFBundle.cpp in Sources */,
+ 26CE05F1115C387C0022F371 /* PseudoTerminal.cpp in Sources */,
+ 2660D9CE1192280900958FBD /* StringExtractor.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB914F08733D8E0010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 112;
+ FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ STRIP_INSTALLED_PRODUCT = NO;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_BUILDER = "$(USER)";
+ };
+ name = Debug;
+ };
+ 1DEB915008733D8E0010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ CURRENT_PROJECT_VERSION = 112;
+ DEAD_CODE_STRIPPING = YES;
+ FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ STRIPFLAGS = "-x";
+ STRIP_STYLE = debugging;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_BUILDER = "$(USER)";
+ };
+ name = Release;
+ };
+ 262419A11198A93E00067686 /* BuildAndIntegration */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ CURRENT_PROJECT_VERSION = 112;
+ DEAD_CODE_STRIPPING = YES;
+ FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ STRIPFLAGS = "-x";
+ STRIP_STYLE = debugging;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_BUILDER = "$(USER)";
+ };
+ name = BuildAndIntegration;
+ };
+ 262419A21198A93E00067686 /* BuildAndIntegration */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = (
+ x86_64,
+ i386,
+ );
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = 112;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER;
+ INSTALL_PATH = /Developer/usr/bin;
+ LLDB_DEBUGSERVER = 1;
+ OTHER_LDFLAGS = (
+ "-sectcreate",
+ __TEXT,
+ __info_plist,
+ "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
+ );
+ OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
+ PREBINDING = NO;
+ PRODUCT_NAME = debugserver;
+ STRIP_INSTALLED_PRODUCT = YES;
+ USER_HEADER_SEARCH_PATHS = "./source $(DERIVED_SOURCES_DIR)";
+ ZERO_LINK = NO;
+ };
+ name = BuildAndIntegration;
+ };
+ 26CE0596115C31C30022F371 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = (
+ x86_64,
+ i386,
+ );
+ CODE_SIGN_IDENTITY = lldb_codesign;
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = 112;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER;
+ INSTALL_PATH = /Developer/usr/bin;
+ LLDB_DEBUGSERVER = 1;
+ OTHER_LDFLAGS = (
+ "-sectcreate",
+ __TEXT,
+ __info_plist,
+ "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
+ );
+ OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
+ PREBINDING = NO;
+ PRODUCT_NAME = debugserver;
+ USER_HEADER_SEARCH_PATHS = "./source $(DERIVED_SOURCES_DIR)";
+ ZERO_LINK = NO;
+ };
+ name = Debug;
+ };
+ 26CE0597115C31C30022F371 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = (
+ x86_64,
+ i386,
+ );
+ CODE_SIGN_IDENTITY = lldb_codesign;
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = 112;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER;
+ INSTALL_PATH = /Developer/usr/bin;
+ LLDB_DEBUGSERVER = 1;
+ OTHER_LDFLAGS = (
+ "-sectcreate",
+ __TEXT,
+ __info_plist,
+ "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
+ );
+ OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
+ PREBINDING = NO;
+ PRODUCT_NAME = debugserver;
+ USER_HEADER_SEARCH_PATHS = "./source $(DERIVED_SOURCES_DIR)";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "debugserver" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB914F08733D8E0010E9CD /* Debug */,
+ 1DEB915008733D8E0010E9CD /* Release */,
+ 262419A11198A93E00067686 /* BuildAndIntegration */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = BuildAndIntegration;
+ };
+ 26CE05A4115C31ED0022F371 /* Build configuration list for PBXNativeTarget "debugserver" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 26CE0596115C31C30022F371 /* Debug */,
+ 26CE0597115C31C30022F371 /* Release */,
+ 262419A21198A93E00067686 /* BuildAndIntegration */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = BuildAndIntegration;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
diff --git a/lldb/tools/debugserver/resources/lldb-debugserver-Info.plist b/lldb/tools/debugserver/resources/lldb-debugserver-Info.plist
new file mode 100644
index 00000000000..ae9b6b28b11
--- /dev/null
+++ b/lldb/tools/debugserver/resources/lldb-debugserver-Info.plist
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleVersion</key>
+ <string>2</string>
+ <key>SecTaskAccess</key>
+ <array>
+ <string>allowed</string>
+ <string>debug</string>
+ </array>
+</dict>
+</plist>
diff --git a/lldb/tools/debugserver/resources/lldb-debugserver-entitlements.plist b/lldb/tools/debugserver/resources/lldb-debugserver-entitlements.plist
new file mode 100644
index 00000000000..42cfb9cdc0e
--- /dev/null
+++ b/lldb/tools/debugserver/resources/lldb-debugserver-entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>get-task-allow</key>
+ <true/>
+</dict>
+</plist>
diff --git a/lldb/tools/debugserver/scripts/dbgnub-config.pl b/lldb/tools/debugserver/scripts/dbgnub-config.pl
new file mode 100644
index 00000000000..c953cc2e1c5
--- /dev/null
+++ b/lldb/tools/debugserver/scripts/dbgnub-config.pl
@@ -0,0 +1,71 @@
+#!/usr/bin/perl
+
+use strict;
+my $config_file = "$ENV{SCRIPT_OUTPUT_FILE_0}";
+
+# Define the tests we need to run during this configuration
+my @config_tests = (
+ {
+ NAME => "HAVE_64_BIT_MACH_EXCEPTIONS",
+ TEST => "-e '$ENV{SDKROOT}/usr/include/mach/mach_exc.defs'",
+ COMMENT => "// Defined if we can use 64 bit mach exceptions",
+ FAIL => "#undef HAVE_64_BIT_MACH_EXCEPTIONS\
+#define mach_exception_data_t exception_data_t\
+#define mach_exception_data_type_t exception_data_type_t\
+#define mach_exc_server exc_server\
+#define MACH_EXCEPTION_CODES 0\n",
+ SUCCESS => "#define HAVE_64_BIT_MACH_EXCEPTIONS 1\n",
+ }
+);
+
+#----------------------------------------------------------------------
+# Open the config file
+#----------------------------------------------------------------------
+open(CONFIG, "> $config_file") || die "Couldn't open '$config_file' for writing: $!\n";
+print CONFIG "/*" . "-" x 72 . "\n";
+print CONFIG "// This file is auto generated by a dbgnub-config.pl, do not edit by hand!\n";
+print CONFIG "//" . "-" x 72 . "\n";
+print CONFIG "// COMMAND LINE\n";
+print CONFIG "// " . join(' ', @ARGV) . "\n";
+print CONFIG "//" . "-" x 72 . "\n";
+print CONFIG "// ENVIRONMENT\n";
+my $key;
+my $val;
+while (($key, $val) = each %ENV)
+{
+ printf CONFIG "// %s = %s\n", $key, $val;
+}
+print CONFIG "//" . "-" x 72 . "\n";
+print CONFIG "// SETTINGS\n";
+print CONFIG "// config_file: '$config_file'\n";
+print CONFIG "//" . "-" x 72 . "\n";
+print CONFIG "*/\n\n";
+print CONFIG "#ifndef __DBGNUB_CONFIG__\n";
+print CONFIG "#define __DBGNUB_CONFIG__\n";
+
+
+#----------------------------------------------------------------------
+# Run the tests
+#----------------------------------------------------------------------
+foreach my $test_href (@config_tests)
+{
+ if (exists $test_href->{COMMENT}) {
+ print CONFIG "\n$test_href->{COMMENT}\n";
+ } else {
+ print CONFIG "\n// $test_href->{NAME}\n";
+ }
+
+ my $test_result = eval "$test_href->{TEST}";
+ if ($test_result != 0)
+ {
+ print CONFIG "$test_href->{SUCCESS}\n";
+ }
+ else
+ {
+ print CONFIG "$test_href->{FAIL}\n";
+ }
+}
+
+print CONFIG "#endif // #ifndef __DBGNUB_CONFIG__\n";
+close(CONFIG);
+
diff --git a/lldb/tools/debugserver/source/ChangeLog b/lldb/tools/debugserver/source/ChangeLog
new file mode 100644
index 00000000000..2f3843bbc60
--- /dev/null
+++ b/lldb/tools/debugserver/source/ChangeLog
@@ -0,0 +1,1515 @@
+2010-01-29 Greg Clayton <gclayton@apple.com>
+
+ * MachProcess.cpp (MachProcess::PrepareForAttach): No longer use the
+ SBSLaunchApplication macro from the SpringBoard.framework, use the actual
+ function name SBSLaunchApplicationForDebugging.
+ (MachProcess::CleanupAfterAttach): Ditto.
+ (MachProcess::SBForkChildForPTraceDebugging): Ditto.
+ (debugserver-entitlements.plist): Added the "seatbelt-profiles" entitlement
+ so debugserver can be sandboxed.
+
+2009-07-06 Greg Clayton <gclayton@apple.com>
+
+ * MachTask.cpp (MachTask::GetDYLDAllImageInfosAddress): Hack around bad
+ kernel code that renamed the first member of the TASK_DYLD_INFO without
+ any way to detect it has changed.
+
+2009-06-29 Greg Clayton <gclayton@apple.com>
+
+ * DNB.cpp (GetAllInfosMatchingName): Correctly truncate process name string
+ to MAXCOMLEN when searching kinfo_proc structs for process matches by name.
+ * MachProcess.cpp (MachProcess::PrepareForAttach): Added logging when
+ attaching to a program by name.
+
+2009-06-25 Greg Clayton <gclayton@apple.com>
+
+ * DNB.cpp (DNBProcessLaunch): Added a stat on the incoming path that we are
+ about to launch to make sure the file exists. If the file doesn't, then an
+ appropriate error string is returned. Also if we fail to get the task for
+ our process ID, we return an error string right away instead of letting the
+ debug session go for a little bit and then later failing after a few more
+ packets.
+
+2009-04-07 Jim Ingham <jingham@apple.com>
+
+ * RNBRemote.h: Add vAttachWait
+ * RNBRemote.cpp (RNBRemote::CreatePacketTable): Add vattachwait.
+ (RNBRemoteShouldCancelCallback): New function.
+ (RNBRemote::HandlePacket_v): Handle vattachwait.
+ * RNBSocket.cpp (RNBSocket::Read): Mark the connection as closed when the
+ port goes away.
+ * DNB.cpp (DNBProcessAttachByName): New function.
+ (DNBProcessAttach): Make this handle catching the attach when done and
+ dealing with timeout & return conditions.
+ (GetAllInfos): New function.
+ (GetAlInfosMatchingName): New function.
+ (DNBProcessAttachWait): New function.
+ DNB.h: Declare DNBProcessAttachByName, DNBProcessAttachWait, change
+ signature of DNBProcessAttach.
+ * MachProcess.cpp (MachProcess::PrepareForAttach): New function.
+ (MachProcess::CheckForProcess): New function.
+ (MachProcess::CleanupAfterAttach): New function.
+ (CopyBundleIDForPath): New function.
+ (MachProcess::SBForkChildForPTraceDebugging): Convert to using
+ CopyBundleIDForPath.
+ * MachProcess.h: Declare PrepareForAttach, CleanupAfterAttach and
+ CheckForProcess.
+ * DNBTimer.h (TimeOfDayLaterThan): New function.
+ * test-remotenub.cpp (RNBRunLoopGetStartModeFromRemote): Rename from
+ RNBRunLoopGetArgsFromRemote, and handle vattachwait.
+ (RNBRunLoopLaunchAttaching): Code was moved from here into DNBProcessAttach.
+ (StartListening): New function.
+ (GetAllProcessInfos, GetAllProcessInfosMatchingName): Moved to
+ DNBProcess.cpp.
+ (main): Handle attach waitfor, and make debugserver with only a host and
+ port wait on commands from gdb.
+
+2009-04-03 Greg Clayton <gclayton@apple.com>
+
+ * RNBRemote.h (PacketEnum): Added enum for qShlibInfoAddr.
+ * RNBRemote.cpp (RNBRemote::CreatePacketTable) Added the qShlibInfoAddr
+ packet definition to m_packets.
+ (RNBRemote::GetPacket): Log when we run into an unimplemented packet.
+ (RNBRemote::HandleReceivedPacket): Only log the packet when logging
+ LOG_RNB_REMOTE.
+ (RNBRemote::HandlePacket_q): Add support for the new qShlibInfoAddr packet.
+ * DNB.h (DNBProcessGetSharedLibraryInfoAddress): New prototype.
+ * DNB.cpp (DNBProcessGetSharedLibraryInfoAddress): New function.
+ * MachTask.h (MachProcess::GetDYLDAllImageInfosAddress): New prototype.
+ * MachTask.cpp (MachProcess::GetDYLDAllImageInfosAddress): New function.
+
+2009-04-01 Greg Clayton <gclayton@apple.com>
+
+ * test-remotenub.cpp (main): Display the detailed error message if any when
+ attaching fails.
+
+2009-03-25 Greg Clayton <gclayton@apple.com>
+
+ * test-remotenub.cpp (RNBRunLoopGetArgsFromRemote): Cleaned up logging and
+ removed time deltas form the messages.
+ (RNBRunLoopLaunchAttaching): Ditto.
+ (RNBRunLoopLaunchInferior): Ditto and also use new DNBProcessLaunch that
+ takes an error string pointer.
+ * RNBContext.h (class RNBContext): Removed the m_timer member.
+ * RNBContext.cpp (RNBContext::StartProcessStatusThread): Cleaned up logging
+ and removed time deltas form the messages.
+ (RNBContext::ThreadFunctionProcessStatus): Ditto.
+ * RNBSocket.h (class RNBSocket): Removed unused m_last_errno member and
+ accessor functions.
+ * RNBSocket.cpp (RNBSocket::Listen): Cleaned up logging and
+ removed time deltas form the messages.
+ (RNBSocket::ConnectToService): Ditto.
+ (RNBSocket::Read): Ditto.
+ (RNBSocket::Write): Ditto.
+ (RNBSocket::SaveErrno): Removed.
+ (RNBSocket::ClosePort): Don't call RNBSocket::SaveErrno().
+ * RNBRemote.cpp (RNBRemote::RNBRemote): Cleaned up logging and
+ removed time deltas form the messages.
+ (RNBRemote::~RNBRemote): Ditto.
+ (RNBRemote::SendPacket): Ditto.
+ (RNBRemote::GetPacketPayload): Ditto.
+ (RNBRemote::GetPacket): Ditto): Ditto.
+ (RNBRemote::HandleAsyncPacket): Ditto.
+ (RNBRemote::HandleReceivedPacket): Ditto.
+ (RNBRemote::CommDataReceived): Ditto.
+ * DNB.cpp (DNBProcessLaunch): Changed to take a eror string pointer with
+ size for more desciptive error reporting (instead of a uint32_t pointer).
+ * DNB.h (DNBProcessLaunch): Ditto.
+ * DNBError.cpp (DNBError::AsString): Now returns NULL if there is no error.
+ * DNBError.h (DNBError::SetErrorString): New accessor to allow custom error
+ strings.
+ * arm/DNBArchImpl.cpp (DNBArchMachARM::GetGPRState): Improved logging.
+ * MachProcess.cpp (MachProcess::SBForkChildForPTraceDebugging): Improved
+ error messages when a file doesn't exist, or when unable to extract the
+ CFBundleIdentifier.
+ * PThreadEvent.cpp (class PThreadEvent): Commented out all logging calls.
+
+2009-03-07 Greg Clayton <gclayton@apple.com>
+
+ * test-remotenub.cpp (GetAllProcessInfosMatchingName): New function that
+ returns matching kinfo_proc structs given a process name.
+ (main): Enhanced the --attach option to be able to take a PROCNAME or
+ a PID. Changed the --waitfor=PROCNAME option to ignore any existing
+ processes with PROCNAME so we only catch new process invocations.
+
+2009-03-07 Greg Clayton <gclayton@apple.com>
+
+ * RNBRemote.cpp (RNBRemote::HandlePacket_p): Use the correct get current
+ thread function call so we get the correct thread registers.
+
+2009-03-03 Greg Clayton <gclayton@apple.com>
+
+ * test-remotenub.cpp (g_isatty): New global that gets set to non-zero if
+ STDOUT is a TTY in the beginning of main.
+ (RNBLogSTDOUT): New macro that logs to STDOUT if g_isatty is non-zero, else
+ it logs to asl.
+ (RNBLogSTDERR): New macro that logs to STDERR if g_isatty is non-zero, else
+ it logs to asl.
+ (RNBRunLoopGetArgsFromRemote): Use new RNBLogSTDOUT/RNBLogSTDERR macros.
+ (GetAllProcessInfos): Get all process info structs for everything on the
+ system.
+ (main): Implemented new --waitfor=NAME option to allow waiting for a process
+ to run by polling the system processes. The new --waitfor-interval=N option
+ allows fine control over the polling interval where N is the number of mirco
+ seconds (usec) to wait between polls (defaults to 1000). The new
+ --waitfor-duration=N allows a timeout in seconds to be specified when
+ waiting for a process (defaults to infinite).
+
+2009-03-02 Greg Clayton <gclayton@apple.com>
+
+ * DNBArchImpl.cpp (DNBArchMachARM::EvaluateNextInstructionForSoftwareBreakpointSetup):
+ Take care of a case where no instructions execute in a Thumb IT block and
+ the last of which is a branch.
+
+2009-02-10 Greg Clayton <gclayton@apple.com>
+
+ * RNBRemote.h (PacketEnum): Added 'detach' enumeration.
+ (RNBRemote::HandlePacket_D): New member function prototype.
+ * RNBRemote.cpp (RNBRemote::CreatePacketTable): Added detach support.
+ (RNBRemote::HandlePacket_D): New function for detach support.
+
+2009-02-10 Greg Clayton <gclayton@apple.com>
+
+ * RNBRemote.cpp (RNBRemote::HandlePacket_UNIMPLEMENTED): Log this
+ packet with the packet that is unimplemented.
+ (RNBRemote::GetPacket): Call RNBRemote::HandlePacket_UNIMPLEMENTED()
+ when we don't recognize a packet.
+ (RNBRemote::HandleReceivedPacket): Don't reply to packets we don't
+ recognize with unimplemented in this fucntion as that should have
+ already been done for us in RNBRemote::GetPacket().
+
+2009-02-10 Greg Clayton <gclayton@apple.com>
+
+ * RNBRemote.h (PacketEnum): Added query_step_packet_supported.
+ * RNBRemot.cpp (RNBRemote::CreatePacketTable): Added new
+ qStepPacketSupported packet.
+ (RNBRemote::HandlePacket_q): Added support for the new
+ "qStepPacketSupported" packet.
+ (RNBRemote::HandlePacket_G): Some cleanup when reading registers
+ to avoid spurious console logging.
+
+2009-01-30 Greg Clayton <gclayton@apple.com>
+
+ * debugserver-entitlements.plist: Changed the entitlement
+ "run-invalid-allow" to "run-unsigned-code".
+
+2009-01-23 Greg Clayton <gclayton@apple.com>
+
+ * DNBArchImpl.cpp (DNBArchMachARM::EvaluateNextInstructionForSoftwareBreakpointSetup):
+ Merged Yusuf's changes to make software single stepping work.
+ * test-remotenub.cpp (RNBRunLoopLaunchInferior): Call new
+ DNBResolveExecutablePath function to resolve executable paths.
+ * DNB.h (DNBResolveExecutablePath): New function prototype.
+ * DNB.cpp (DNBResolveExecutablePath): New function that will resolve
+ relative paths and also executable paths for executables that aren't relative
+ but yet are in the shell PATH environment variable.
+
+2009-01-22 Greg Clayton <gclayton@apple.com>
+
+ * DNBArchImpl.h (class DBNArchMachARM): Renamed member variable
+ m_chained_hw_single_step_addr to m_hw_single_chained_step_addr. Added
+ new member variables: m_sw_single_step_itblock_break_id, m_last_decode_pc,
+ and m_sw_single_step_itblock_break_count. Renamed m_thumbStaticData to
+ m_last_decode_thumb, and renamed m_decodedInstruction to m_last_decode_arm.
+ (DBNArchMachARM::DecodeITBlockInstructions): New prototype.
+ (DBNArchMachARM::DecodeInstructionUsingDisassembler): New prototype.
+ (DBNArchMachARM::BreakpointHit): New prototype.
+ * DNBArchImpl.cpp (DNBArchMachARM::ThreadDidStop): Disable any of the
+ many software single step breakpoints if any are set.
+ (DNBArchMachARM::StepNotComplete): Changed renamed member accesses.
+ (DNBArchMachARM::DecodeITBlockInstructions): New function for software
+ single stepping through Thumb IT blocks.
+ (DNBArchMachARM::EnableHardwareSingleStep): Cleaned up logging.
+ (DNBArchMachARM::ComputeNextPC): Ditto.
+ (DNBArchMachARM::EvaluateNextInstructionForSoftwareBreakpointSetup): Now
+ properly handles Thumb IT software single stepping.
+ (DNBArchMachARM::SetSingleStepSoftwareBreakpoints): Ditto.
+ (DNBArchMachARM::DecodeInstructionUsingDisassembler): New function.
+ (DNBArchMachARM::BreakpointHit): New breakpoint callback function.
+
+2009-01-21 Greg Clayton <gclayton@apple.com>
+
+ * MachProcess.cpp (MachProcess::PrivateResume): Set the process state before
+ we actually resume so we are sure to get the events in the correct order.
+
+2009-01-16 Greg Clayton <gclayton@apple.com>
+
+ * RNBRemote.cpp (RNBRemote::HandlePacket_last_signal): Include only
+ registers which are to be expedited in the T packets.
+ (RNBRemote::HandlePacket_p): Enable for all targets.
+ (struct register_map_entry): Added an expedite member so we know which
+ registers need to be sent up to the host with each stop reply packet.
+ (register_map): Updated each array members' expedite member with an
+ appropriate value.
+
+2009-01-16 Greg Clayton <gclayton@apple.com>
+
+ * RNBRemote.cpp (RNBRemote::HandlePacket_s): Enabled the step command ("s"
+ packet) for ARM now that libdebugnub.dylib can do both hardware and software
+ single stepping.
+
+2009-01-13 Greg Clayton <gclayton@apple.com>
+
+ *DNBArchImpl.cpp (bit): New function.
+ (bits): New function.
+ (DNBArchMachARM::ConditionPassed): Use new "bit" function.
+ (DNBArchMachARM::ComputeNextPC): Use new "bit" function, remove inline
+ assembly for "RSC" instruction so this compiles for armv7 (which defaults
+ to thumb)
+ (DNBArchMachARM::NumSupportedHardwareBreakpoints): Use new "bits" function.
+ (DNBArchMachARM::NumSupportedHardwareWatchpoints): Use new "bits" function.
+
+2009-01-12 Greg Clayton <gclayton@apple.com>
+
+ * DNBArch.h (DNBArchProtocol::NumSupportedHardwareBreakpoints()): Removed
+ the "const" qualifier to allow arches to auto detect how many hardware
+ breakpoints they have.
+ (DNBArchProtocol::NumSupportedHardwareWatchpoints()): Removed the "const"
+ qualifier to allow arches to auto detect how many hardware watchpoints they
+ have.
+ * DNBArchImpl.h (DNBArchMachARM::NumSupportedHardwareBreakpoints()): Auto
+ detect how many BRP pairs are avialable and disable for armv7 for the time
+ being (rdar://problem/6372672).
+ (DNBArchMachARM::NumSupportedHardwareWatchpoints()): Auto detect how many
+ WRP pairs are avialable and disable for armv7 for the time being
+ (rdar://problem/6372672).
+
+2009-01-09 Greg Clayton <gclayton@apple.com>
+
+ * test-remotenub.cpp (main): Filled in short argument versions for
+ --applist (-t) and --lockdown (-k) options.
+ * DNBArchImpl.h (DNBArchMachARM::ConditionPassed): New protected
+ member function.
+ (DNBArchMachARM::ComputeNextPC): New protected member function.
+ (DNBArchMachARM::EvaluateNextInstructionForSoftwareBreakpointSetup): New
+ protected member function.
+ (DNBArchMachARM::m_thumbStaticData): New protected member variable.
+ (DNBArchMachARM::m_decodedInstruction): New protected member variable.
+ * DNBArchImpl.cpp (DNBArchMachARM::ThreadDidStop): Added extra code that
+ will log and exit when we are verifying software single stepping (a
+ compile time option).
+ (DNBArchMachARM::ConditionPassed): New function.
+ (DNBArchMachARM::ComputeNextPC): New function.
+ (DNBArchMachARM::EvaluateNextInstructionForSoftwareBreakpointSetup): New
+ function.
+ (DNBArchMachARM::SetSingleStepSoftwareBreakpoints): Added the guts of the
+ software single stepping.
+ (DNBArchMachARM::NumSupportedHardwareBreakpoints): Prepared for adding
+ auto detection code.
+ (DNBArchMachARM::NumSupportedHardwareWatchpoints): Prepared for adding
+ auto detection code.
+
+2008-12-11 Greg Clayton <gclayton@apple.com>
+
+ * DNB.h (DNBProcessWaitForEvent): Renamed to DNBProcessWaitForEvents.
+ (DNBProcessSetEvents): Removed (deprecated).
+ (DNBProcessGetWaitForResetMask): Removed (unused).
+ (DNBProcessSetWaitForResetMask): Removed (unused).
+ (DNBProcessInterruptEvents): New function prototype.
+ * DNB.cpp (DNBProcessWaitForEvent): Renamed to DNBProcessWaitForEvents.
+ (DNBProcessSetEvents): Removed (deprecated).
+ (DNBProcessGetWaitForResetMask): Removed (unused).
+ (DNBProcessSetWaitForResetMask): Removed (unused).
+ (DNBProcessInterruptEvents): New function that can be used to
+ asynchronously interrupt infinite wait for events calls.
+ RNBRemote.cpp (RNBRemote::HandlePacket_v): Call DNBProcessWaitForEvents.
+ RNBContext.cpp (RNBContext::ThreadFunctionProcessStatus): Ditto.
+ test-remotenub.cpp (RNBRunLoopLaunchInferior): Ditto.
+ (RNBRunLoopLaunchAttaching): Ditto.
+
+2008-12-11 Greg Clayton <gclayton@apple.com>
+
+ * DNB.cpp (GetProcessMap): Use new PTHREAD_MUTEX_LOCKER macro to ease
+ debugging of deadlocks.
+ (DNBProcessLaunch): Improved logging.
+ (DNBProcessMemoryRead): Call MachProcess::ReadMemory so breakpoint
+ opcodes can be removed from memory.
+ (DNBProcessMemoryWrite): Call MachProcess::WriteMemory so that we work
+ around enabled software breakpoint traps.
+ * DNBLog.cpp (GetLogThreadedMutex): New function.
+ (_DNBLogThreaded): Use new PTHREAD_MUTEX_LOCKER macro to ease
+ debugging of deadlocks.
+ (_DNBLogThreadedIf): Ditto.
+ * DNBBreakpoint.h (DNBBreakpoint::IntersectsRange): New function.
+ * DNBBreakpoint.cpp (DNBBreakpointList::FindIDByAddress): Improved
+ logging.
+ * MacOSX/MachThread.cpp (MachThread::MachThread): Improved logging.
+ (MachThread::~MachThread): Ditto.
+ (MachThread::Suspend): Ditto.
+ (MachThread::Resume): Ditto.
+ (MachThread::RestoreSuspendCount): Ditto.
+ (MachThread::GetState): Use new PTHREAD_MUTEX_LOCKER macro to ease
+ debugging of deadlocks.
+ (MachThread::SetState): Ditto.
+ * MacOSX/MachVMMemory.cpp (MachVMMemory::Read): Improved logging.
+ (MachVMMemory::Write): Ditto.
+ (MachVMMemory::WriteRegion): Ditto.
+ * MacOSX/MachProcess.cpp (MachProcess::GetState): Use new
+ PTHREAD_MUTEX_LOCKER macro to ease debugging of deadlocks.
+ (MachProcess::SetState): Ditto.
+ (MachProcess::Clear): Ditto.
+ (MachProcess::PrivateResume): Ditto.
+ (MachProcess::ReplyToAllExceptions): Ditto.
+ (MachProcess::ExceptionMessageReceived): Ditto.
+ (MachProcess::AppendSTDOUT): Ditto.
+ (MachProcess::GetAvailableSTDOUT): Ditto.
+ (MachProcess::ThreadFunctionSTDIO): Renamed from to
+ MachProcess::STDIOThread.
+ (MachProcess::StartSTDIOThread): Improved logging.
+ (MachProcess::CreateBreakpoint): Ditto.
+ (MachProcess::CreateWatchpoint): Ditto.
+ (MachProcess::DisableAllBreakpoints): Ditto.
+ (MachProcess::DisableBreakpoint): Ditto.
+ (MachProcess::DisableWatchpoint): Ditto.
+ (MachProcess::EnableBreakpoint): Ditto.
+ (MachProcess::EnableWatchpoint): Ditto.
+ (MachProcess::LaunchForDebug): Ditto.
+ (MachProcess::PosixSpawnChildForPTraceDebugging): Ditto.
+ (MachProcess::Detach): Reset the running event bit after resuming prior
+ to issuing the SIGSTOP to avoid a pause.
+ (MachProcess::RemoveTrapsFromBuffer): New function that removes
+ breakpoint traps from a memory buffer.
+ (MachProcess::ReadMemory): Read memory from the task, then removes any
+ breakpoint traps prior to returning the buffer.
+ (MachProcess::WriteMemory): Write memory and any needed data to the
+ breakpoint saved opcodes for any software breakpoint traps that are
+ enabled.
+ * MacOSX/MachProcess.h (MachProcess::ThreadFunctionException): Removed.
+ (MachProcess::ThreadFunctionSTDIO): Renamed to MachProcess::STDIOThread().
+ (MachProcess::RemoveTrapsFromBuffer): New function.
+ * MacOSX/MachVMRegion.cpp (MachVMRegion::SetProtections): Improved
+ logging.
+ (MachVMRegion::RestoreProtections): Ditto.
+ (MachVMRegion::GetRegionForAddress): Ditto.
+ * MacOSX/MachException.cpp (catch_mach_exception_raise_state): Improved
+ logging.
+ (catch_mach_exception_raise_state_identity): Ditto.
+ (catch_mach_exception_raise): Ditto.
+ (MachException::Message::Dump): Ditto.
+ (MachException::Data::GetStopInfo): Ditto.
+ (MachException::Message::Receive): Ditto.
+ (MachException::Message::Reply): Ditto.
+ (MachException::Data::Dump): Ditto.
+ (MachException::PortInfo::Save): Ditto.
+ (MachException::PortInfo::Restore): Ditto.
+ * MacOSX/MachTask.cpp (MachTask::Suspend): Improved logging.
+ (MachTask::Resume): Ditto.
+ (MachTask::ReadMemory): Ditto.
+ (MachTask::WriteMemory): Ditto.
+ (MachTask::TaskPortForProcessID): Ditto.
+ (MachTask::BasicInfo): Ditto.
+ (MachTask::StartExceptionThread): Ditto.
+ (MachTask::ShutDownExcecptionThread): Ditto and use pthread_cancel to
+ interrupt the exception thread.
+ (MachTask::ExceptionThread): Ditto and revert back to infinite timeout
+ as pthread_cancel will break us out of infinite mach_msg receive calls.
+ * MacOSX/MachThreadList.cpp (MachThreadList::UpdateThreadList): Improved
+ logging.
+ (MachThreadList::CurrentThread): Use new PTHREAD_MUTEX_LOCKER macro to
+ ease debugging of deadlocks.
+ * DNBTimer.h (DNBTimer::DNBTimer): Initialize the mutex with a recursive
+ pthread.
+ (DNBTimer::Reset): Use new PTHREAD_MUTEX_LOCKER macro to ease debugging
+ of deadlocks.
+ (DNBTimer::TotalMicroSeconds): Ditto.
+ (DNBTimer::GetTime): Ditto.
+ (DNBTimer::ElapsedMicroSeconds): Ditto.
+ (DNBTimer::GetTimeOfDay): New class function.
+ * DNBError.cpp (DNBError::LogThreaded): Improved logging.
+ * test-dbgnub.cpp
+ * PThreadMutex.h: Added the ability to debug deadlocks by defining
+ DEBUG_PTHREAD_MUTEX_DEADLOCKS.
+ * FunctionProfiler.cpp
+ * PThreadEvent.cpp (PThreadEvent::NewEventBit): Use new
+ PTHREAD_MUTEX_LOCKER macro to ease debugging of deadlocks.
+ (PThreadEvent::FreeEventBits): Ditto.
+ (PThreadEvent::GetEventBits): Ditto.
+ (PThreadEvent::ReplaceEventBits): Ditto.
+ (PThreadEvent::SetEvents): Ditto.
+ (PThreadEvent::ResetEvents): Ditto.
+ (PThreadEvent::WaitForSetEvents): Ditto.
+ (PThreadEvent::WaitForEventsToReset): Ditto.
+
+2008-12-05 Greg Clayton <gclayton@apple.com>
+
+ * DNBDefs.h (LOG_TASK): New log bit.
+ * DNB.cpp (DNBProcessIsAlive): User newly abtracted MachTask class.
+ (DNBProcessMemoryRead): Ditto.
+ (DNBProcessMemoryWrite): Ditto.
+ * DNBArchImpl.cpp (DNBArchMachARM::EnableHardwareSingleStep): Ditto.
+ (DNBArchMachARM::SetSingleStepSoftwareBreakpoints) Ditto.
+ * MachException.cpp (MachException::Message::Receive): Cleaned up logging
+ so it doesn't always log timeout errors.
+ (MachException::Message::Reply): Use abstracted MachTask class for any
+ task related queries.
+ (MachException::PortInfo::Save): Cleaned up logging.
+ (MachException::PortInfo::Restore): Cleaned up logging and now return an
+ error instead of the number of restored port infos.
+ * MachProcess.cpp (class MachProcess): Abstracted out all of the task_t
+ related stuff (suspend, resuyme, exception ports, exception thread, and
+ more) into a new class MachTask.
+ (MachProcess::Task): Now returns a reference to a MachTask class.
+ (MachProcess::Clear): Uses new abstracted MachTask class.
+ (MachProcess::Detach): Ditto.
+ (MachProcess::PrivateResume): Ditto.
+ (MachProcess::DisableBreakpoint): Ditto.
+ (MachProcess::ExceptionMessageReceived): Ditto.
+ (MachProcess::ExceptionMessageBundleComplete): Ditto.
+ (MachProcess::AttachForDebug): Ditto.
+ (MachProcess::LaunchForDebug): Ditto.
+ (MachProcess::SBLaunchForDebug): Ditto.
+ (MachProcess::TaskIsValid): Removed (replaced by similar functionality
+ in the new MachTask class).
+ (MachProcess::ExceptionPort): Ditto.
+ (MachProcess::ExceptionPortIsValid): Ditto.
+ (MachProcess::StartExceptionThread): Ditto.
+ (MachProcess::Suspend): Ditto.
+ (MachProcess::TaskResume): Ditto.
+ (MachProcess::TaskBasicInfo): Ditto.
+ (MachProcess::TaskBasicInfo): Ditto.
+ (MachProcess::ReadMemory): Ditto.
+ (MachProcess::WriteMemory): Ditto.
+ (MachProcess::ThreadFunctionException): Ditto.
+
+2008-12-04 Greg Clayton <gclayton@apple.com>
+
+ * DNB.h (DNBProcessSetEvents): New API function prototype.
+ * DNB.cpp (DNBProcessSetEvents): New API function.
+ (DNBProcessHalt): Send our process a SIGINT instead of suspending
+ the task.
+ * DNBDefs.h (NUB_STATE_IS_STOPPED): Removed up duplicate entry in macro.
+ (eEventPrcoessAsyncInterrupt): New prcoess event bit that allows async
+ interrupting of infinite DNBProcessWaitForEvent() function calls.
+ * MachException.cpp (MachException::Message::Receive): Improved logging.
+ (MachException::Message::Reply): Improved logging.
+ * MachProcess.h (MachProcess::TaskBasicInfo): New member and static
+ functions.
+ * MachProcess.cpp (MachProcess::TaskIsValid): Use new TaskBasicInfo()
+ member function.
+ (MachProcess::Resume): Removed the detach parameter from the PrivateResume()
+ function call.
+ (MachProcess::Kill): Added a absolute timeout pointer to allow callers to
+ wait for the signal to be received if the timeout is non-NULL.
+ (MachProcess::TaskBasicInfo): New member and static function.
+ (MachProcess::TaskResume): New function that resumes the task by making sure
+ the suspend count is correctly ref counted.
+ (MachProcess::Detach): When detaching from a process make sure it is
+ stopped (SIGSTOP) first, then we can successfully detach. The exception
+ thread now also properly exits.
+ (MachProcess::PrivateResume): Call new TaskResume function, and removed the
+ detach functionality.
+ (MachProcess::DisableBreakpoint): Only notify the thread list that a
+ breakpoint has changed if the breakpoint is going to be removed.
+ (MachProcess::ThreadFunctionException): Added a permanent 1 second timeout
+ for each call to mach_msg() so we can exit the thread in the event that
+ we detach from a process/task.
+ * test-debugnub (main): Modified to show an example of how to detach using
+ a signal_handler to asynchronously receive a SIGINT and properly interrupt
+ and detach from a running process.
+
+2008-11-26 Greg Clayton <gclayton@apple.com>
+
+ * DNBDefs.h (LOG_STEP): New logging define.
+ * DNBError.cpp (DNBError::LogThreaded): If there is no error, then
+ log with "success: " as a prefix instead of "error: ".
+ * arm/DBNArchImpl.cpp (DNBArchMachARM::EnableHardwareSingleStep): Log using
+ new LOG_STEP instead of LOG_BREAKPOINTS.
+ (DNBArchMachARM::SetSingleStepSoftwareBreakpoints): Ditto.
+ * MachException.cpp (MachException::Message::Dump): Log excetion header
+ and reply header on two separate lines.
+ * MachProcess.cpp (IsSBProcess): Check for NULL CFArrayRef returned from
+ SBSCopyApplicationDisplayIdentifiers for SkankPhone.
+ (MachProcess::Suspend): Check if process state is not running instead of
+ having to receive an event after a timeout if one is given.
+ (MachProcess::Detach): Deallocate the exception port when detaching and
+ restore the inferior task exception ports prior to clearing and detaching.
+ (MachProcess::PrivateResume): Grab the task's basic info and make sure we
+ get the resume the correct number of times.
+ (MachProcess::DisableBreakpoint): Removed unused variable opcode_restored
+ and make sure the breakpoint is enabled before we start warning that
+ our opcode wasn't there.
+ * ppc/DBNArchImpl.cpp (DNBArchMachPPC::EnableHardwareSingleStep): Log
+ using LOG_STEP instead of LOAD_BREAKPOINTS.
+ * RNBServices.cpp (IsSBProcess): Check for NULL CFArrayRef returned from
+ SBSCopyApplicationDisplayIdentifiers for SkankPhone.
+
+2008-11-26 Greg Clayton <gclayton@apple.com>
+
+ * MachProcess.h (MachProcess::Suspend): Now takes an optional absolute
+ timeout that, if non-NULL, will case the function to return after the
+ process has been suspended and is in a stopped state. If the timeout is
+ NULL, then no waiting will occur.
+ * MachProcess.cpp (MachProcess::Suspend): Ditto.
+ (MachProcess::Detach): Now replies to all exceptions, un-suspends all
+ threads and resumes the task.
+ (MachProcess::ReplyToAllExceptions): New function.
+ (MachProcess::PrivateResume): Now takes an additional parameter named
+ detach that will do the right thing when detaching from a process.
+ * DNBArchImpl.h (DNBArchMachI386::ThreadWillResume): Returns void.
+ * DNBArchImpl.cpp (DNBArchMachI386::ThreadWillResume): Returns void.
+ * RNBServices.cpp (ListApplications): #ifdef-ed for ARM only as it
+ currently uses SpringBoard.
+ (IsSBProcess): Ditto.
+ * test-remotenub.cpp (RNBRunLoopLaunchInferior): #ifdef-ed around
+ ARM parts so it compiles for i386.
+ (main): Ditto.
+
+2008-11-24 Greg Clayton <gclayton@apple.com>
+
+ * DNBArchProtocol.h (DNBArchProtocol::ThreadWillResume): Now returns void.
+ * DNBArchImpl.cpp (DNBArchMachARM::ThreadWillResume): Returns void and
+ has hollowed out support for software single step.
+ (DNBArchMachARM::ThreadDidStop): Has a debug mode that uses hardware single
+ step to verify software single step that can be enabled by defining
+ DNB_ARCH_MACH_ARM_DEBUG_SW_STEP.
+ (DNBArchMachARM::SetSingleStepSoftwareBreakpoints): New function.
+ * DNBArchImpl.h (DNBArchMachARM::ThreadWillResume): Returns void.
+ (DNBArchMachARM::SetSingleStepSoftwareBreakpoints): New prototype.
+ (DNBArchMachARM::m_sw_single_step_next_pc): New member variable.
+ (DNBArchMachARM::m_sw_single_step_break_id): New member variable.
+ * MachThread.cpp (MachThread::ThreadWillResume): Now returns void.
+ * MachThread.h (MachThread::ThreadWillResume): Now returns void.
+
+2008-11-19 Greg Clayton <gclayton@apple.com>
+
+ * DNBError.h (FlavorType): Added SpringBoard error type for arm builds.
+ * DNBError.cpp (DNBError::AsString): Now returns SpringBoard error strings
+ if the error type is SpringBoard.
+ * test-remotenub.cpp (RNBRunLoopLaunchInferior): Set the error into
+ RNBContext as either a POSIX error or a SpringBoard error.
+ * RNBContext.h (m_launch_status): Changed this member to be a DNBError
+ instead of a uint32_t.
+ (RNBContext::LaunchStatus): Now returns a reference to the DNBError object
+ in m_launch_status.
+ * RNBContext.cpp (RNBContext::LaunchStatusAsString): Let DNBError handle
+ any error string descriptions, including SpringBoard errors.
+ * RNBRemote.cpp (RNBRemote::HandlePacket_q): Use new error class in
+ RNBContext.
+ (RNBRemote::HandlePacket_C): Return without an erroneous error when resuming
+ a process with a signal.
+ * DNBArch.h (DNBArchProtocol::StepNotComplete): New protocol function with
+ default return value.
+ * DNBArchImpl.cpp (DNBArchMachARM::StepNotComplete): New function.
+ (DNBArchMachARM::EnableHardwareSingleStep): Handle hardware single stepping
+ over 32 bit thumb instructions better so we always do a true instruction
+ level single step.
+ * MachProcess.cpp (MachProcess::ExceptionMessageBundleComplete): Now resumes
+ if single stepping wasn't able to complete in a single run.
+ * MachThread.cpp (MachThread::ShouldStop): Fills in new step_more parameter
+ if stepping is not complete.
+ * MachThreadList.cpp (MachThreadList::ShouldStop): Pass step_more parameter
+ to each MachThread::ShouldStop call.
+
+2008-11-13 Greg Clayton <gclayton@apple.com>
+
+ * MachProcess.cpp (MachProcess::PosixSpawnChildForPTraceDebugging): Don't
+ call posix_spawnattr_setbinpref_np when launching with posix_spawn on ARM
+ targets as it currently selects the incorrect slice due to multiple slices
+ that contain the same cputype, yet they all have differing cpusubtypes.
+
+2008-11-04 Greg Clayton <gclayton@apple.com>
+
+ * RNBRemote.h (GetContinueThread): Don't return the current thread when
+ the continue thread is zero or -1.
+ * RNBRemote.cpp (RNBRemote::HandlePacket_c): Resume the process if we
+ have no continue thread set.
+ (RNBRemote::HandlePacket_s): Ditto.
+ (RNBRemote::HandlePacket_C): Ditto unless a continue address is specified
+ in which case we will only succeed if we have one thread when the continue
+ with signal and address doesn't have a continue thread specified.
+ (RNBRemote::HandlePacket_S): Ditto.
+ * DNB.cpp (DNBProcessResumeWithSignal): New function.
+ (DNBProcessResume): Added better logging.
+ (DNBProcessHalt): Ditto.
+ (DNBThreadResume): Ditto.
+ (DNBThreadResumeWithSignal): Ditto.
+ * DNB.h (DNBProcessResumeWithSignal): New prototype.
+ * DNBError.cpp (DNBError::LogThreaded): New function.
+ * DNBError.h (DNBError::LogThreaded): New prototype.
+ * DNBLog.cpp (_DNBLogThreaded): Added sequence ID for threaded logs.
+ (_DNBLogThreadedIf): Ditto.
+ * MachException.cpp (MachException::Data::GetStopInfo): Use new SoftSignal()
+ accessor.
+ (MachException::Data::DumpStopReason): Ditto.
+ (MachException::Message::Reply): Added better logging and log using the
+ soft signal if our task matches that in the exception.
+ (MachException::Data::Dump): Added better logging.
+ * MachException.h (IsSoftSignal): Removed.
+ (SoftSignal): New function that returns the soft signal in the exception
+ data if there is one, or zero otherwise.
+ * MachProcess.cpp (MachProcess::Suspend): Improved logging.
+ (MachProcess::Resume): Ditto.
+ (MachProcess::PrivateResume): Handle the case where the process is told
+ to resume with a signal by matching the signal up to the thread that had
+ the soft signal if no thread id is specified.
+ * MachThread.cpp (MachThread::Suspend): Improved logging.
+ (MachThread::Resume): Improved logging.
+ (MachThread::RestoreSuspendCount): Improved logging.
+ (MachThread::Resume): Improved logging.
+ (MachThread::Dump): Improved logging.
+ * MachThreadList.cpp (MachThreadList::Dump): Improved logging.
+
+2008-10-22 Greg Clayton <gclayton@apple.com>
+
+ * test-remotenub.cpp (RNBRunLoopMode): Added a new enum value
+ eRNBRunLoopModeInferiorAttaching.
+ (g_long_options): Added "--attach=PID" for attaching to existing processes
+ and "--launch=(auto|posix|fork|springboard)" options.
+ (RNBRunLoopLaunchInferior): Now launches process with new
+ nub_launch_flavor_t enum that can be overridden with the --launch option.
+ (RNBRunLoopLaunchAttaching): New function for attaching to existing
+ processes.
+ (main): Added command line option support for the "--attach" and "--launch"
+ options and added attach to pid support and better logging.
+ * DNB.cpp/h: (DNBProcessLaunch): Added nub_launch_flavor_t and error
+ parameter for more precise control when launching processes.
+ (DNBProcessSBLaunch): Removed function as launching with SpringBoard can
+ now be done using DNBProcessLaunch with launch_flavor being set to
+ eLaunchTypeSpringBoard (arm only).
+ (DNBProcessSBAttach): Removed function (SpringBoard processes are now auto
+ detected in the MachProcess::AttachForDebug function on ARM).
+ * DNBDefs.h (NUB_GENERIC_ERROR): New generic error definition.
+ (nub_launch_flavor_t): New enumeration used for control over process
+ launching.
+ * MachProcess.cpp (IsSBProcess): New function.
+ (MachProcess::AttachForDebug): Removed flags parameter that was being used
+ for SpringBoard flags and we now detect if a process belongs to SpringBoard
+ by calling IsSBProcess.
+ (MachProcess::LaunchForDebug): Now has launch parameter that tells it how
+ to launch the inferior process and there is also an error code that gets
+ returned. This function can now launch using fork + exec, posix_spawn,
+ or SpringBoard on ARM targets.
+ (MachProcess::SBLaunchForDebug): Now uses DNBError reference instead of
+ uint32_t pointer for the error code.
+ (MachProcess::SBForkChildForPTraceDebugging): Ditto.
+
+2008-10-22 Greg Clayton <gclayton@apple.com>
+
+ * MacOSX/arm/DNBArchImpl.cpp (DNBArchMachARM::GetRegisterValue): Set
+ register value to a uint32 value instead of a float64 value for s0 -
+ s31.
+
+2008-10-17 Greg Clayton <gclayton@apple.com>
+
+ * test-remotenub.cpp (RNBRunLoopLaunchInferior): Don't listen for
+ the qLaunchSuccess if we aren't doing a lockdown connnection.
+
+2008-10-13 Greg Clayton <gclayton@apple.com>
+
+ * RNBRemote.h (class RNBRemote): Added m_watchpoints member.
+ * DNB.cpp (DNBBreakpointSet): Added boolean hardware parameter for
+ requesting that a hardware breakpoint be set.
+ (DNBWatchpointSet): New function.
+ (DNBWatchpointClear): New function.
+ (DNBWatchpointGetHitCount): New function.
+ (DNBWatchpointGetIgnoreCount): New function.
+ (DNBWatchpointSetIgnoreCount): New function.
+ (DNBWatchpointSetCallback): New function.
+ (DNBWatchpointPrint): New function.
+ * DNBRegisterInfo.cpp (DNBRegisterValueClass::Dump): Modified to emit
+ a single DNBLog() call so there aren't multiple newlines when logging
+ to ASL.
+ * RNBContext.cpp (RNBContext::ThreadFunctionProcessStatus): Use new
+ process state changed events.
+ * DNBBreakpoint.h (class DNBBreakpoint): Removed m_state member and
+ added m_tid, m_enabled, m_hw_preferred, m_is_watchpoint, m_watch_read,
+ m_watch_write, and m_hw_index.
+ (DNBBreakpoint::ThreadID()): New accessor.
+ (DNBBreakpoint::IsEnabled()): New accessor.
+ (DNBBreakpoint::SetEnabled()): New accessor.
+ (DNBBreakpoint::IsWatchpoint()): New accessor.
+ (DNBBreakpoint::IsBreakpoint()): New accessor.
+ (DNBBreakpoint::SetIsWatchpoint()): New accessor.
+ (DNBBreakpoint::WatchpointRead()): New accessor.
+ (DNBBreakpoint::WatchpointWrite()): New accessor.
+ (DNBBreakpoint::HardwarePreferred()): New accessor.
+ (DNBBreakpoint::IsHardware()): New accessor.
+ (DNBBreakpoint::GetHardwareIndex()): New accessor.
+ (DNBBreakpoint::SetHardwareIndex()): New accessor.
+ (DNBBreakpoint::ThreadID()): New accessor.
+ (DNBBreakpoint::GetState()): Removed accessor.
+ (DNBBreakpoint::SetState()): Removed accessor.
+ (DNBBreakpoint::AddBreakpoint()): Renamed to Add().
+ (DNBBreakpoint::RemoveBreakpoint()): Renamed to Remove().
+ (DNBBreakpoint::FindBreakIDForAddress()): Renamed to FindIDByAddress().
+ (DNBBreakpoint::ShouldStopAtBreakpoint()): Renamed to ShouldStop().
+ (DNBBreakpoint::SetBreakpointCallback()): Renamed to SetCallback().
+ (DNBBreakpoint::FindBreakpointWithAddress()): Renamed to
+ FindByAddress().
+ (DNBBreakpoint::FindBreakpointWithBreakID()): Renamed to FindByID().
+ (DNBBreakpoint::GetBreakpointAtIndex()): Renamed to GetByIndex().
+ * FunctionProfiler.h: New header for subclass of DNBRuntimeAction.
+ * RNBRemote.cpp (RNBRemote::HandlePacket_v): Use new process state
+ changed events.
+ (RNBRemote::HandlePacket_z): Implement the hardware breakpoint and
+ watchpoint commands z1, Z1, z2, Z2, z3 and Z3
+ * PThreadEvent.h (PThreadEvent::GetEventBits): Made member function
+ const.
+ (PThreadEvent::WaitForSetEvents): Ditto.
+ (PThreadEvent::WaitForEventsToReset): Ditto.
+ (PThreadEvent::WaitForResetAck): Ditto.
+ (PThreadEvent::m_mutex): Made class member mutable.
+ (PThreadEvent::m_set_condition): Made class member mutable.
+ (PThreadEvent::m_reset_condition): New mutable class member.
+ * ProfileObjectiveC.cpp
+ * DNBArch.h (DNBArch::NotifyException): Now has default implementation
+ that returns false.
+ (DNBArch::NumSupportedHardwareBreakpoints): New virtual member
+ function with a default implementation.
+ (DNBArch::NumSupportedHardwareWatchpoints): Ditto.
+ (DNBArch::EnableHardwareBreakpoint): Ditto.
+ (DNBArch::EnableHardwareWatchpoint): Ditto.
+ (DNBArch::DisableHardwareBreakpoint): Ditto.
+ (DNBArch::DisableHardwareWatchpoint): Ditto.
+ * DNB.h (DNBBreakpointSet): New take a HARDWARE parameter that allows
+ requests for setting hardware breakpoints.
+ (DNBWatchpointSet): New function prototype.
+ (DNBWatchpointClear): New function prototype.
+ (DNBWatchpointGetHitCount): New function prototype.
+ (DNBWatchpointGetIgnoreCount): New function prototype.
+ (DNBWatchpointSetIgnoreCount): New function prototype.
+ (DNBWatchpointSetCallback): New function prototype.
+ (DNBWatchpointPrint): New function prototype.
+ * MacOSX/arm/DNBArchImpl.cpp: Added hardware breakpoint and watchpoint
+ support for ARM.
+ (DNBArchMachARM::GetCPUType): New function.
+ (DNBArchMachARM::DumpDBGState): New function.
+ (DNBArchMachARM::GetDBGState): New function.
+ (DNBArchMachARM::SetDBGState): New function.
+ (DNBArchMachARM::EnableHardwareSingleStep): New function.
+ (DNBArchMachARM::EnableHardwareBreakpoint): New function.
+ (DNBArchMachARM::NotifyException): Removed.
+ (DNBArchMachARM::DisableHardwareBreakpoint): New function.
+ (DNBArchMachARM::EnableHardwareWatchpoint): New function.
+ (DNBArchMachARM::DisableHardwareWatchpoint): New function.
+ * MacOSX/MachThread.cpp (MachThread::Suspend): Added better logging.
+ (MachThread::Resume): Ditto.
+ (MachThread::RestoreSuspendCount): Ditto.
+ (MachThread::Dump): Ditto.
+ (MachThread::EnableHardwareBreakpoint): New function.
+ (MachThread::EnableHardwareWatchpoint): New function.
+ (MachThread::DisableHardwareBreakpoint): New function.
+ (MachThread::DisableHardwareWatchpoint): New function.
+ * MacOSX/MachThreadList.h (MachThreadList::GetLastError): Removed.
+ (MachThread::EnableHardwareBreakpoint): New prototype.
+ (MachThread::DisableHardwareBreakpoint): New prototype.
+ (MachThread::EnableHardwareWatchpoint): New prototype.
+ (MachThread::DisableHardwareWatchpoint): New prototype.
+ (class MachThread): Remove m_err member variable.
+ * MacOSX/ppc/DNBArchImpl.cpp (DNBArchMachPPC::GetCPUType) New
+ function.
+ (DNBArchMachPPC::NotifyException): Removed.
+ * MacOSX/ppc/DNBArchImpl.h (DNBArchMachPPC::NotifyException): Removed.
+ * MacOSX/MachThread.h (MachThread::EnableHardwareBreakpoint): New
+ prototype.
+ (MachThread::EnableHardwareWatchpoint): New prototype.
+ (MachThread::DisableHardwareBreakpoint): New prototype.
+ (MachThread::DisableHardwareWatchpoint): New prototype.
+ (class MachThread): Renambed class member m_exception to
+ m_stop_exception.
+ * MacOSX/MachProcess.cpp (MachProcess::SetState): Updated to use new
+ process event enumerations.
+ (MachProcess::PrivateResume): Added better logging.
+ (MachProcess::CreateBreakpoint): Added bool HARDWARE parameter for
+ requesting hardware breakpoints.
+ (MachProcess::CreateWatchpoint): New function.
+ (MachProcess::DisableAllWatchpoints): New function.
+ (MachProcess::DisableWatchpoint): New function.
+ (MachProcess::DumpWatchpoint): New function.
+ (MachProcess::EnableBreakpoint): Enabled breakpoints in hardware if
+ requested and supported.
+ (MachProcess::DisableBreakpoint): Disable hardware breakpoints if that
+ is how they were set.
+ (MachProcess::EnableWatchpoint): New function.
+ (MachProcess::ExceptionMessageBundleComplete): Wait for the
+ eEventProcessRunningStateChanged event to be reset before changing
+ state to stopped to avoid race condition with very fast start/stops.
+ (MachProcess::LaunchForDebug): Added posix_spawn support.
+ (MachProcess::PosixSpawnChildForPTraceDebugging): New function.
+ * MacOSX/i386/DNBArchImpl.cpp (DNBArchMachI386::GetCPUType): New
+ function.
+ * MacOSX/i386/DNBArchImpl.h (DNBArchMachI386::GetCPUType): New
+ prototype.
+ * MacOSX/MachProcess.h (PosixSpawnChildForPTraceDebugging): New
+ prototype.
+ * MacOSX/MachException.cpp (class MachException::ThreadMessage):
+ Renamed class to MachException::Data.
+ * MacOSX/MachThreadList.cpp (class MachThreadList): Removed m_err
+ class member.
+ (MachThreadList::EnableHardwareBreakpoint): New function.
+ (MachThreadList::DisableHardwareBreakpoint): New function.
+ (MachThreadList::EnableHardwareWatchpoint): New function.
+ (MachThreadList::DisableHardwareWatchpoint): New function.
+ * MacOSX/MachException.h (class MachException::ThreadMessage):
+ Renamed class to MachException::Data.
+ * DNBDefs.h (nub_watch_t): New typedef.
+ (INVALID_NUB_HW_INDEX): New macro definition.
+ (WATCH_TYPE_READ): New macro definition.
+ (WATCH_TYPE_WRITE): New macro definition.
+ (NUB_STATE_IS_RUNNING): New macro to see if state is a running state.
+ (NUB_STATE_IS_STOPPED): New macro to see if state is a stopped state.
+ (eEventProcessStateChanged): Deprecated.
+ (eEventProcessRunningStateChanged): New process event state.
+ (eEventProcessStoppedStateChanged): New process event state.
+ (LOG_WATCHPOINTS): New macro definition for logging watchpoints.
+ * test-remotenub.cpp (RNBRunLoopLaunchInferior): Use new process
+ event states.
+ * FunctionProfiler.cpp: New class that allows single stepping through
+ an address range for tracing exact call graphs.
+
+2008-09-22 Greg Clayton <gclayton@apple.com>
+
+ * RNBRemote.h (GetContinueThread): If the continue thread is zero or
+ -1 then return GetCurrentThread().
+ * RNBRemote.cpp (m_packets): Made the vCont functions call
+ RNBRemote::HandlePacket_v().
+ (RNBRemote::HandlePacket_H): Cleaned up whitespace.
+ (RNBRemote::HandlePacket_last_signal): Return actual signal values for
+ EXE_SOFTWARE/EXC_SOFT_SIGNAL mach exceptions.
+ (RNBRemote::HandlePacket_v): Implemented the 'vCont?' and 'vCont;'
+ packets.
+ (RNBRemote::HandlePacket_c): Handle the case where an address is
+ provided.
+ (RNBRemote::HandlePacket_C): Implemented the continue with signal
+ including when an address is provided.
+ (RNBRemote::HandlePacket_S): Implemented the step with signal
+ including when an address is provided.
+ * DNB.cpp (DNBProcessResume): Pass 0 as the signal when resuming
+ a process without specifying a thread.
+ (DNBThreadResume): Pass 0 as the signal when resuming a specific thread.
+ (DNBThreadResumeWithSignal): New function.
+ * DNB.h (DNBThreadResumeWithSignal): New prototype.
+ * MachException.h (MachException::Message::Reply): Added a signal
+ parameter.
+ * MachException.cpp (MachException::Message::Reply): Update the thread
+ with the new SIGNAL parameter instead of always zero so signals can be
+ passed on to programs.
+ * MachProcess.h (MachProcess::Resume): Added a signal parameter.
+ * MachProcess.h (MachProcess::PrivateResume): Added a signal parameter.
+ * MachProcess.cpp (MachProcess::Resume): Pass new SIGNAL parameter to
+ MachProcess::PrivateResume.
+ * MachProcess.cpp (MachProcess::PrivateResume): Pass new SIGNAL
+ parameter to the mach exception reply.
+
+2008-08-08 Greg Clayton <gclayton@apple.com>
+
+ * DNB.cpp (gProcessMap): Removed static C++ global.
+ (GetProcessMap): New Function.
+ (AddProcessToMap): New function.
+ (RemoveProcessFromMap): New function.
+ (GetProcessSP): Use new GetProcessMap function to get process list.
+
+2008-07-30 Greg Clayton <gclayton@apple.com>
+
+ * debugserver-entitlements.plist (get-task-allow): Removed.
+ (run-invalid-allow): Added boolean value set to TRUE.
+
+2008-04-18 Greg Clayton <gclayton@apple.com>
+
+ * MachProcess.cpp (MachProcess::Task): Added getuid(), geteuid(),
+ getgid(), getegid() to the log message if task for pid fails.
+
+2008-04-07 Greg Clayton <gclayton@apple.com>
+
+ * RNBContext.cpp (RNBContext::LaunchStatusAsString): Removed unused
+ tmp_str variable.
+
+2008-04-04 Greg Clayton <gclayton@apple.com>
+
+ * CFString.cpp/h (UTF8): Made a static function that can convert
+ a CFStringRef to UTF8.
+
+2008-04-04 Greg Clayton <gclayton@apple.com>
+
+ * test-remotenub.cpp (main): Make sure we exit after we send the
+ application list.
+
+2008-04-04 Greg Clayton <gclayton@apple.com>
+
+ * RNBServices.h (IsSBProcess): New prototype;
+ * RNBServices.cpp (IsSBProcess): New function that returns true it
+ SpringBoard owns or knows about the process.
+ * RNBRemote.cpp (RNBRemote::HandlePacket_v): Made attach work correctly.
+ * DNB.cpp (DNBProcessSBAttach): New function for use when attaching to
+ a process owned by SpringBoard.
+ (DNBProcessAttach): Fixed an issue where a local was shadowing a
+ parameter.
+ * DNB.h (DNBProcessSBAttach): New prototype.
+ * MachProcess.cpp (MachProcess::AttachForDebug): AttachForDebug now
+ takes some flags so it knows to enable SpringBoard functionality.
+ * MachProcess.h (MachProcess::AttachForDebug): Added flags parameter
+ to prototype.
+
+2008-04-04 Greg Clayton <gclayton@apple.com>
+
+ * test-remotenub.cpp (RNBRunLoopGetArgsFromRemote): Handle the new
+ attach packet and watch for connection being lost.
+ (main): handle the --applist option when there we aren't using lockdown
+ by printing the results to stdout and exiting with appropriate error code
+ if we failed. Also handle the new prototype for ListApplications.
+ * RNBServices.h (ListApplications): Change first parameter to be a std::string
+ that will get the contents of the plist so we can use this for more than
+ just lockdown.
+ * RNBServices.cpp (ListApplications): Change first parameter to be a std::string
+ that will get the contents of the plist so we can use this for more than
+ just lockdown and also fixed the logic so we actually create a full list of
+ applications instead of just overwriting the first entry.
+ * RNBRemote.h (PacketEnum): Added a new 'vattach' enum for the "vAttach;PID"
+ gdb remote command.
+ (RNBRemote::HandlePacket_v): New prototype;
+ * RNBRemote.cpp (RNBRemote::CreatePacketTable): add the vattach packet definition
+ to m_packets.
+ (RNBRemote::HandlePacket_v): New function that handles attach to a process.
+
+2008-04-03 Jim Ingham <jingham@apple.com>
+
+ * RNBRemote.h: Add query_launch_success to packet enum.
+ * RNBRemote.cpp (RNBRemote::CreatePacketTable_): Add query_launch_success.
+ (HandlePacket_q): Handle query_launch_success.
+ * DNB.cpp (DNBProcessSBLaunch): Pass in launch_retval.
+ * DNB.h: Change prototype of DNBProcessSBLaunch to take launch_retval.
+ * RNBContext.cpp (RNBContext::LaunchStatusAsString): New function.
+ * RNBContext.h (RNBContext): Add m_launch_status & accessors.
+ * macosx/MachProcess.cpp (MachProcess::SBLaunchForDebug): Pass launch_retval.
+ (MachProcess::SBForkChildForPTraceDebugging): Accept & set launch_retval.
+ * Macosx/MachProcess.h: Change prototypes of SBLaunchForDebug &
+ ForkChildForPTraceDebugging to accept launch_retval.
+ * test-remotenub.cpp (RNBRunLoopLaunchInferior): Get the launch status and
+ put it in the context, then wait for the qLaunchStatus packet.
+
+2008-04-03 Greg Clayton <gclayton@apple.com>
+
+ * com.apple.debugserver.plist: Changed plist so debugserver
+ runs as mobile user.
+ * com.apple.debugserver.applist.plist: Ditto.
+
+2008-04-03 Greg Clayton <gclayton@apple.com>
+
+ * MachProcess.cpp: (MachProcess::SBForkChildForPTraceDebugging):
+ Increased SBS application launch timeout to 30 seconds.
+
+2008-03-27 Christopher Friesen <friesen@apple.com>
+
+ * RNBServices.h: Pass tasks from SpringBoard as a plist
+ * RNBServices.cpp: Ditto.
+ * test-remotenub.cpp: added --applist flag
+ * com.apple.debugserver.applist.plist: Agent plist
+
+2008-03-17 Jim Ingham <jingham@apple.com>
+
+ * DNB.h: Pass envp to DNBProcessLaunch & DNBProcessSBLaunch.
+ * DNB.cpp: Ditto.
+ * MachProcess.h: Ditto for *LaunchForDebug and
+ *ForkChildForPtraceDebugging.
+ * MachProcess.cpp (MachProcess::LaunchForDebug): Pass on envp.
+ (MachProcess::SBLaunchForDebug): Ditto.
+ (MachProcess::ForkChildForPtraceDebugging): Accept envp, haven't actually
+ implemented the passing yet.
+ (MachProcess::SBForkChildForPtraceDebuggin): Accept envp, convert to
+ CFDictionary and pass to SBSLaunchApplication.
+ * RNBContext.h: Add environment to the context.
+ * RBNContext.cpp (RNBContext::EnvironmentAtIndex): New function.
+ * RNBRemote.h: Add set_environment_variable to the PacketEnum.
+ * RNBRemote.cpp (RNBRemote::CreatePacketTable): Add QEnvironment:.
+ * (RNBRemote::HandlePacket_Q): Ingest the environment variable.
+ * test-remotenub.cpp (RNBRunLoppLaunchInferior): Convert the env
+ array in the context into an array, and pass it to the DNBProcess*Launch
+ methods.
+
+2008-03-17 Greg Clayton <gclayton@apple.com>
+
+ * DNBBreakpoint.cpp (DNBBreakpointList::GetBreakpointAtIndex): New
+ functions (const and non-const versions).
+ * DNBBreakpoint.h (DNBBreakpointList::GetBreakpointAtIndex): New
+ prototypes (const and non-const versions).
+ * DNBError.h (DNBError::Success()): Don't use KERN_SUCCESS define.
+ (DNBError::Fail()): Don't use KERN_SUCCESS define.
+ * MachProcess.cpp (MachProcess::DisableAllBreakpoints): New function.
+ (MachProcess::Detach): Added initial implementation that will halt
+ the process, disable all breakpoints and call PT_DETACH.
+ * MachProcess.h (MachProcess::DisableAllBreakpoints): New prototype.
+
+2008-03-04 Greg Clayton <gclayton@apple.com>
+
+ * RNBRemote.h (RNBRemote::SendHexEncodedBytePacket): New prototype.
+ * RNBRemote.cpp (RNBRemote::SendHexEncodedBytePacket): New function.
+ (RNBRemote::SendSTDOUTPacket): Use SendHexEncodedBytePacket function
+ to send bytes.
+ (RNBRemote::SendSTDERRPacket): Ditto.
+ (RNBRemote::HandlePacket_q): Return a valid thread info string for
+ qThreadExtraInfo queries.
+ * DNB.cpp (DNBThreadPrintStopReason): Commented out unused function.
+ (DNBThreadGetInfo): New function.
+ * DNB.h (DNBThreadPrintStopReason): Commented out prototype.
+ (DNBThreadGetInfo): New prototype.
+ * MachProcess.cpp (MachProcess::GetThreadInfo): New function.
+ * MachProcess.h (MachProcess::GetThreadInfo): New prototype.
+ * MachThreadList.cpp (MachThreadList::GetThreadInfo): New function.
+ * MachThreadList.h (MachThreadList::GetThreadInfo): New prototype.
+ * MachThread.cpp (MachThread::GetBasicInfoAsString): New function.
+ (MachThread::InferiorThreadID): New function.
+ * MachThread.cpp (MachThread::GetBasicInfoAsString): New prototype.
+ (MachThread::InferiorThreadID): New prototype.
+
+2008-02-27 Greg Clayton <gclayton@apple.com>
+
+ * RNBRemote.cpp (RNBRemote::HandlePacket_last_signal): Set the
+ current thread when we notify a thread has stopped to subsequent
+ g and p packets get the correct data.
+
+2008-02-26 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.h: Add query_thread_extra_info enum.
+ * RNBRemote.cpp: Add support for qThreadExtraInfo.
+ Currently we return 'Ok' as the packet status for
+ every thread.
+
+2008-02-26 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.cpp (RNBRemote::HandlePacket_q): Correct handling
+ of qfThreadInfo/qsThreadInfo.
+
+2008-02-20 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.h: Change default for gdb's max incoming packet size to
+ reflect the real default size.
+ * RNBRemote.cpp (HandlePacket_Q): Correct the string comparisions for
+ the QSetMaxPayloadSize and QSetMaxPacketSize packets.
+
+2008-02-19 Christopher Friesen <friesen@apple.com>
+
+ * CFDataFormatters.c: CoreFoundation data formatters added to project.
+
+2008-02-19 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.h: Record the max payload size, not the max packet
+ size for less ambiguous meaning.
+ * RNBRemote.cpp: Add support for QSetMaxPayloadSize: packet which
+ should have a clearer meaning than QSetMaxPacketSize.
+ QSetMaxPacketSize will be removed once we get have a chance to get
+ a new debugserver and gdb submitted.
+
+2008-02-18 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.h: Make default size 1024.
+ * RNBRemote.cpp: Questionmark packet should stay under
+ max_packet_size - 5 to allow for start, end, checksum and nul
+ char bytes.
+
+2008-02-18 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.h: Add m_max_packet_size to class defn.
+ * RNBRemote.cpp: Initialize it, use it.
+
+2008-02-18 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.h: Add set_max_packet_size.
+ * RNBRemote.cpp: Add QSetMaxPacketSize packet handling.
+
+2008-02-18 Greg Clayton <gclayton@apple.com>
+
+ * test-remotenub.cpp (HandleProcessStateChange): Call new
+ RNBRemote::FlushSTDIO function.
+ (RNBRunLoopInferiorExecuting): Ditto.
+ * RNBRemote.h (RNBRemote::FlushSTDIO): New prototype.
+ * RNBRemote.cpp (RNBRemote::FlushSTDIO): New function to
+ centralize the stdio.
+
+2008-02-18 Greg Clayton <gclayton@apple.com>
+
+ * DNB.cpp (DNBProcessWaitForEvent): Added timeout pointer as
+ parameter that can be NULL for infinite timeout to simplify
+ the DNB interface.
+ (DNBProcessTimedWaitForEvent): Removed function.
+ * DNB.h (DNBProcessWaitForEvent): Added timeout argument.
+ (DNBProcessTimedWaitForEvent): Removed prototype.
+ * DNBTimer.h (DNBTimer::OffsetTimeOfDay): New function.
+ * CFString.cpp (CFString::GetLength() const): New function.
+ * CFString.h (CFString::GetLength() const): New prototype.
+ * MachProcess.h (MachProcess class): Removed m_attached and
+ added m_flags.
+ * MachProcess.cpp (MachProcess::AttachForDebug): Set m_flags
+ to indicate we attached.
+ (MachProcess::SBLaunchForDebug): Set m_flags to indicate we
+ attached using SpringBoard and that we attached.
+ (MachProcess::SBForkChildForPTraceDebugging): Changed to new
+ SpringBoardServices API.
+ (MachProcess::ThreadFunctionException): Added code that will
+ renew a watchdog assertion when we launch apps through
+ SpringBoardServices.
+ * PThreadEvent.cpp (PThreadEvent::WaitForSetEvents): Simplified
+ PThreadEvent API to have only one version of WaitForSetEvents
+ that has an optional timeout pointer argument.
+ * RNBContext.cpp (RNBContext::StopProcessStatusThread): Adapt
+ to new PThreadEvent API changes.
+ (RNBContext::ThreadFunctionProcessStatus): Adapt to new
+ DNBProcessWaitForEvent API changes.
+ * RNBRemote.cpp (RNBRemote::StopReadRemoteDataThread): Adapt
+ to new PThreadEvent API changes.
+ * test-remotenub.cpp (RNBRunLoopLaunchInferior): Adapt to new
+ DNBProcessWaitForEvent API changes.
+ (RNBRunLoopInferiorExecuting): Process STDIO first, then
+ incoming packets.
+
+2008-02-14 Jason Molenda (jmolenda@apple.com)
+
+ * MachProcess.cpp: (MachProcess::SBForkChildForPTraceDebugging):
+ Set mode bits on slave side of pty.
+
+2008-02-12 Greg Clayton <gclayton@apple.com>
+
+ * DNB.cpp (DNBEnableLogging): Removed function.
+ (DNBThreadPrintStopReason): Removed the file handle from this
+ function and use DNBLog calls.
+ * DNB.h (DNBEnableLogging): Removed function prototype.
+ (DNBThreadPrintStopReason): Removed the file handle
+ from the function prototype in favor of using DNBLog calls.
+ * DNBDataRef.cpp (DNBDataRef::Dump): Removed file handle to use
+ DNBLog for the logging and print a log line each time a full line
+ is ready for output after caching it in a local buffer.
+ * DNBDataRef.cpp (DNBDataRef::Dump): Removed file handle from
+ prototype.
+ * DNBDefs.h (DNBCallbackLog): New callback prototype for all
+ logging.
+ DNBLog.cpp(g_debug_opt): Renamed to d_debug and made it a file
+ static.
+ (DNBLogGetDebug): New accessor function for g_debug.
+ (DNBLogSetDebug): New accessor function for g_debug.
+ (g_verbose): Made into a file static and added accessors.
+ (DNBLogGetVerbose): New accessor function for g_verbose.
+ (DNBLogSetVerbose): New accessor function for g_verbose.
+ (DNBLogSetLogCallback): New function call that registers a logging
+ callback for all logging in libdebugnub.dylib and any code that
+ loads it.
+ (DNBLogToASL): Removed function as it is deprecated in favor of
+ using DNBLogSetLogCallback to regsiter a callback function that
+ implements the logging.
+ (DNBLogToFile): Ditto.
+ (DNBLogCloseLogFile): Ditto.
+ (DNBLogToFile): Ditto.
+ (DNBLogToFile): Ditto.
+ (_DNBLogPuts): Removed unused function.
+ (_DNBLogVAPrintf): Calls the callback function to do the logging
+ if one has been registered.
+ * DNBLog.h (DNBLOG_FLAG_FATAL): New defines that get passed to
+ any registered logging callback functions.
+ (DNBLOG_FLAG_FATAL): Ditto.
+ (DNBLOG_FLAG_ERROR): Ditto.
+ (DNBLOG_FLAG_WARNING): Ditto.
+ (DNBLOG_FLAG_DEBUG): Ditto.
+ (DNBLOG_FLAG_VERBOSE): Ditto.
+ (DNBLOG_FLAG_THREADED): Ditto.
+ (DNBLog*): All logging calls are now exported from libdebugnub.dylib
+ so there aren't two copies (one in debugserver and one in debugnub).
+ C99 vararg Macros wrap all logging calls so no var arg processing
+ occurs when logging is disabled.
+ * DNBRegisterInfo.cpp (DNBRegisterValueClass::Dump): Removed file
+ handle and now use DNBLog calls.
+ * DNBRegisterInfo.h (DNBRegisterValueClass::Dump): Removed file
+ handle from prototype.
+ * MachException.cpp (catch_mach_exception_raise_state_identity):
+ Removed newlines from logging call.
+ (catch_mach_exception_raise): Ditto.
+ (MachException::Message::Dump): Removed file handle from params
+ and removed newlines from logging call.
+ (MachException::ThreadMessage::DumpStopReason): Removed file handle
+ from params and use DNBLog for logging output.
+ (MachException::ThreadMessage::Dump): Log using DNBLog instead of
+ file handle.
+ * MachProcess.cpp (MachProcess::DumpThreadStoppedReason): Ditto.
+ (MachProcess::ReadMemory): Ditto.
+ (MachProcess::WriteMemory): Ditto.
+ (ExceptionMessageBundleComplete): Ditto.
+ * MachThread.cpp (MachThread::Dump): Ditto.
+ (MachThread::DumpRegisterState): Ditto.
+ * MachThreadList.cpp (MachThreadList::DumpThreadStoppedReason): Ditto.
+ (MachThreadList::Dump): Ditto.
+ * RNBRemote.cpp (set_logging): Use new function callback registration
+ calls when enabling ASL logging.
+ test-remotenub.cpp (ASLLogCallback): New function to handle all ASL
+ logging. This function gets registered with libdebugnub.dylib when we
+ want to log using ASL.
+ (FileLogCallback): New function to handle all file logging. This
+ function gets registered with libdebugnub.dylib when we want to log
+ to a 'FILE *'.
+ (main): Register the logging callback functions when we want to log
+ to file or using ASL.
+
+2008-02-12 Greg Clayton <gclayton@apple.com>
+
+ * test-remotenub.cpp (main): Default to ASL logging with no log
+ bits set to allow for warning and error logging.
+ * RNBRemote.h (struct Breakpoint): New structure for ref counting
+ breakpoints in Z and z packets.
+ * RNBRemote.cpp (RNBRemote::SendPacket): Use new LOG_RNB_PACKETS
+ defined when logging actual packet content.
+ (RNBRemote::HandleAsyncPacket): Ditto.
+ (RNBRemote::HandleReceivedPacket): Ditto.
+ (RNBRemote::HandlePacket_z): Ref count the setting and removing
+ of breakpoints with the Z and z packets using new struct
+ RNBRemote::Breakpoint.
+ * RNBDefs.h (LOG_RNB_PACKETS): New define for logging the sending
+ and receiving of packets data.
+ * DNB.cpp (DNBPrintf): Check for NULL file handle.
+ * DNBBreakpoint.cpp (DNBBreakpoint::Dump): Ditto.
+ (DNBBreakpointList::Dump): Ditto.
+ * DNBDefs.h (LOG_EVENTS): New define for logging PThreadEvent.
+ * DNBLog.cpp (g_debug_opt): Relocated outside of #if that turns off
+ logging completely to allow option parsing code that uses it to
+ still compile.
+ (g_verbose): Ditto.
+ * DNBLog.h (DNBLogToASL): Added prototype for when logging is
+ disabled via preprocessor macro.
+ (DNBLogToFile): Ditto.
+ * DNBRegisterInfo.cpp (DNBRegisterValueClass::Dump): Check for NULL
+ file handle.
+ * MachException.cpp (MachException::ThreadMessage::DumpStopReason): Ditto.
+ (MachException::ThreadMessage::Dump): Ditto.
+ * MachProcess.cpp (MachProcess::CreateBreakpoint): Improved logging.
+ (MachProcess::DisableBreakpoint): Verify the original opcode gets
+ restored, improved logging and added unconditional logging for when
+ things go wrong.
+ (MachProcess::EnableBreakpoint): Verify the breakpoint opcode gets
+ written, improved logging and added unconditional logging for when
+ things go wrong.
+ * MachThread.cpp (MachThread::Dump): Check for NULL file handle.
+ * MachVMMemory.cpp (MachVMMemory::WriteRegion): Flush caches in inferior
+ after writing to inferior memory.
+ * PThreadEvent.cpp: Changed all logging calls to key off of LOG_EVENTS
+ instead of LOG_VERBOSE.
+ MachDYLD.cpp (MachDYLD::Dump): Check for NULL file handle.
+ (MachDYLD::DYLIBInfo::Dump): Ditto.
+ ProfileObjectiveC.cpp (ProfileObjectiveC::DumpStats): Ditto.
+
+2008-02-09 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.cpp (set_logging): Log to ASL unconditionally when
+ processing a QSetLogging packet.
+
+2008-02-06 Greg Clayton <gclayton@apple.com>
+
+ * test-remotenub.cpp (main): Dup stdout and stderr to /dev/NULL
+ when we use lockdown.
+
+2008-02-06 Greg Clayton <gclayton@apple.com>
+
+ * RNBSocket.cpp (RNBSocket::Disconnect): Removed unused var ERR.
+ * RNBRemote.cpp(RNBRemote::HandlePacket_Q): Removed unused var PID.
+ * DNBError.cpp (DNBError::LogThreadedIfError): Removed unused var
+ ERR_MSG.
+ * test-remotenub.cpp (RNBRunLoopLaunchInferior): Removed unused
+ variable EXECUTABLE_LENGTH.
+ (main): Removed unused variable ARG_IDX.
+
+2008-02-06 Chris Marcellino (cmarcellino@apple.com) and Myke Olson (molson@apple.com)
+
+ * MachProcess.cpp (SBForkChildForPTraceDebugging): Bring up to date with
+ current SpringBoardServices.framework types and imports.
+
+2008-02-05 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.cpp (set_logging): Remove the mode=file and filename=
+ options to the QSetLogging packet. We're only going to support logging
+ to ASL for now. Logging to a file can still be accomplished by the
+ -l command line argument.
+
+2008-02-02 Christopher Friesen (cfriesen@apple.com)
+
+ * Added libXcodeDebugerSupport.dylib target
+ * XCDebuggerIntrospection.[hc]: Support for Xcode's debugger introspection.
+
+2008-02-01 Jason Molenda (jmolenda@apple.com)
+
+ * DNBLog.cpp (DNBLogCloseLogFile): New function to close a logfile
+ at exit.
+ * DNBLog.h: Prototype.
+ * test-remotenub.cpp (main): Close the log file before exiting.
+
+2008-02-01 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.cpp (set_logging): Recognize the "filename=" argument
+ to the QSetLogging directive.
+ * DNBLog.cpp (DNBLogGetLogMask): New fun.c
+ * DNBLog.h: Prototype.
+
+2008-01-31 Jason Molenda (jmolenda@apple.com)
+
+ * DNBLog.cpp: Add ASL logging as a run-time selectable option.
+ (DNBLogToASL, DNBLogToFile): Functions to switch between logging to
+ a file and logging via ASL.
+ * DNBLog.h: Prototypes.
+ * RNBRemote.cpp (set_logging): Recognize the "mode=" field to enable
+ asl logging. Skip unrecognized keys.
+
+2008-01-31 Greg Clayton (gclayton@apple.com)
+
+ * DNB.cpp (sigchld_handler): Better logging when we get a
+ SIGCHILD and we are watching for process related logging events.
+ * test-remotenub.cpp (RNBRunLoopInferiorExecuting): Only reset
+ events when we still have event bits set.
+
+2008-01-29 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.h: Add set_logging_mode.
+ * RNBRemote.cpp (RNBRemote::CreatePacketTable): Recognize
+ QSetLogging.
+
+2008-01-29 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.cpp (set_logging): New function to parse the QSetLogging
+ packet.
+ (RNBRemote::HandlePacket_Q): Call it.
+
+2008-01-28 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.h: Minimal packet size is 1024 in our gdb now.
+ * RNBRemote.cpp: Add the stop_pc value in big-endian order to the
+ T response packet to make it a little easier to follow where gdb
+ is stepping.
+
+2008-01-28 Greg Clayton <gclayton@apple.com>
+
+ * RNBContext.h: Removed m_pid_state from RNBContext class so that
+ it couldn't get out of sync with the actual process and its accessors
+ SetProcessState() and GetProcessState().
+ * RNBContext.cpp (RNBContext::ProcessStateRunning): Always return the
+ current state of the process instead of a cached value.
+ * test-remotenub.cpp (RNBRunLoopLaunchInferior): Remove call to
+ deprecated RNBContext::SetProcessState().
+ (HandleProcessStateChange): Ditto.
+
+2008-01-24 Greg Clayton (gclayton@apple.com)
+
+ * RNBRemote.cpp (RNBRemote::HandlePacket_q): See if command starts with
+ "qSymbol" (no trailing "s") and return the empty string.
+
+2008-01-24 Greg Clayton (gclayton@apple.com)
+
+ * RNBRemote.cpp (RNBRemote::HandlePacket_q): See if command starts with
+ "qSymbols" and return the empty string.
+
+2008-01-24 Greg Clayton (gclayton@apple.com)
+
+ * DNBError.h (DNBError::DumpIfError): Removed prototype.
+ * DNBError.cpp (DNBError::DumpIfError): Removed function.
+ (DNBError::LogThreadedIfError): Output error as hex.
+ * MachException.cpp (MachException::Message::Receive): Don't use
+ DNBError::DumpIfError, now use DNBError::LogThreadedIfError.
+ * MachProcess.cpp (MachProcess::StartExceptionThread): Ditto.
+ (MachProcess::Suspend): Ditto.
+ (MachProcess::SBForkChildForPTraceDebugging): Ditto.
+ * MachVMMemory.cpp (MachVMMemory::Read): Cleaned up logging
+ calls.
+ (MachVMMemory::Write): Ditto.
+ (MachVMMemory::WriteRegion): Added logging.
+ * RNBContenxt.cpp (display_thread_info): Removed function.
+ * RNBRemote.cpp (RNBRemote::GetPacket): Commented out stderr
+ messages to avoid SpringBoard from killing us.
+ (RNBRemote::HandlePacket_p): Ditto.
+ (RNBRemote::HandlePacket_P): Ditto.
+ (RNBRemote::HandlePacket_c): Ditto.
+ (RNBRemote::HandlePacket_A): Removed code that was already
+ * RNBSocket.cpp (RNBSocket::Listen): Commented out stdout
+ messages to avoid SpringBoard from killing us.
+ (RNBSocket::ConnectToService): Ditto.
+
+2008-01-24 Jim Ingham <jingham@apple.com>
+
+ * RNBRemote.cpp (RNBRemote::HandlePacket_q): Reply "" to qSymbols
+ and qOffsets.
+
+2008-01-23 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.h: m_noack_mode to RNBRemote class.
+ * RNBRemote.cpp: Change #ifdef NO_ACKS code blocks
+ to use m_noack_mode instance variable.
+ (RNBRemote::HandlePacket_Q): New function to handle
+ QStartNoAckMode packet and set m_noack_mode appropriately.
+ * test-remotenub.cpp: Remove NO_ACKS ifdefs.
+
+2008-01-22 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.cpp (RNBRemote::CreatePacketTable): Recognize
+ QStartNoAckMode as an unsupported remote protocol request.
+ * RNBRemote.h: Add start_noack_mode enum entry.
+
+2008-01-22 Greg Clayton (gclayton@apple.com)
+
+ * DNBLog.h: Removed C++ namespace for DNBLog (changed all DNBLog::
+ to DNBLog) so C99 var arg macros can be used to completely disable
+ all logging and any functions that may be called when making the
+ variable arguments.
+ * DNBLog.cpp: Ditto.
+ * DNB.cpp: Ditto.
+ * DNBBreakpoint.cpp: Ditto.
+ * DNBError.cpp: Ditto.
+ * MacOSX/MachDYLD.cpp: Ditto.
+ * MacOSX/MachException.cpp: Ditto.
+ * MacOSX/MachProcess.cpp: Ditto.
+ * MacOSX/MachThread.cpp: Ditto.
+ * MacOSX/MachThreadList.cpp: Ditto.
+ * MacOSX/MachVMMemory.cpp: Ditto.
+ * MacOSX/MachVMRegion.cpp: Ditto.
+ * MacOSX/arm/DNBArchImpl.cpp: Ditto.
+ * MacOSX/ppc/DNBArchImpl.cpp: Ditto.
+ * PThreadEvent.cpp: Ditto.
+ * RNBContext.cpp: Ditto.
+ * RNBRemote.cpp: Ditto.
+ * RNBSocket.cpp: Ditto.
+ * test-remotenub.cpp: Ditto.
+
+2008-01-21 Jason Molenda (jmolenda@apple.com)
+
+ * test-remotenub.cpp: Add NO_SPRINGBOARD for turning off SpringBoard
+ dependency ala NO_ACKS.
+
+2008-01-18 Jason Molenda (jmolenda@apple.com)
+
+ * RNBSocket.h (RNBSocket::RNBSocket): Take either a port # or
+ an already-opened socket, with a boolean to indicate which it is.
+ * RNBRemote.cpp (RNBRemote::RNBRemote): Ditto.
+ * RNBRemote.h: Prototype update.
+ * test-remotenub.cpp: Include lockdown.h. Take --lockdown command
+ line arg, get the socket from liblockdown.dylib instead of opening
+ our own socket if it is specified. --lockdown indicates that
+ the program name/args will be provided via remote protocol instead
+ of on the command line.
+
+2008-01-17 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.cpp: Add NO_ACKS #ifdefs around code that computes
+ the checksums and sends/expects the gdb remote protocol ACK packets.
+ If NO_ACKS is defined, debugserver will not send or expect acks.
+ * test-remotenub.cpp (main): Print a different version string
+ if NO_ACKS is defined.
+
+2008-01-16 Greg Clayton (gclayton@apple.com)
+
+ * PThreadEvent.cpp: Added this pointer to all logging calls.
+
+2008-01-16 Greg Clayton (gclayton@apple.com)
+
+ * RNBSocket.cpp (RNBSocket::Connect()): Use TCP so we can try the
+ TCP_NODELAY socket option.
+ (RNBSocket::SetSocketOption()): New function.
+ * RNBSocket.h (RNBSocket::SetSocketOption()): New class function.
+
+2008-01-14 Jason Molenda (jmolenda@apple.com)
+
+ * RNBRemote.cpp (RNBRemote::HandlePacket_last_signal): When printing
+ registers, skip over gdb regs which don't map to DNB regs.
+
+2008-01-14 Jim Ingham <jingham@apple.com>
+
+ * ChangeLog - created.
+ * RBNContext.h: Added m_arg_vec and accessors.
+ * RNBContext.cpp (SetProcessID): New function.
+ * RBNRemote.h: Added packet type to HandlePacket & HandleAsyncPacket
+ * RNBRemote.cpp (HandlePacket, HandleAsyncPacket): Return type.
+ (HandlePacket_A): Fix a few bugs.
+ (HandlePacket_H): Return OK if target is not yet running.
+ (HandlePacket_q): Return PID of 0 if target is not yet running.
+ * testremotenub.cpp (RNBRunLoopGetArgsFromRemote): Implement.
+ (RNBRunLoopLaunchInferior): Fetch arguments from context.
+ (main) Store arguments in context, call RNBRunLoopGetArgsFromRemote
+ if appropriate.
diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp
new file mode 100644
index 00000000000..72a111bab2c
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNB.cpp
@@ -0,0 +1,1996 @@
+//===-- DNB.cpp -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 3/23/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DNB.h"
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/sysctl.h>
+#include <map>
+#include <vector>
+
+#include "MacOSX/MachProcess.h"
+#include "MacOSX/MachTask.h"
+#include "CFString.h"
+#include "DNBLog.h"
+#include "DNBDataRef.h"
+#include "DNBThreadResumeActions.h"
+#include "DNBTimer.h"
+
+typedef std::tr1::shared_ptr<MachProcess> MachProcessSP;
+typedef std::map<nub_process_t, MachProcessSP> ProcessMap;
+typedef ProcessMap::iterator ProcessMapIter;
+typedef ProcessMap::const_iterator ProcessMapConstIter;
+
+static size_t GetAllInfos (std::vector<struct kinfo_proc>& proc_infos);
+static size_t GetAllInfosMatchingName (const char *process_name, std::vector<struct kinfo_proc>& matching_proc_infos);
+
+//----------------------------------------------------------------------
+// A Thread safe singleton to get a process map pointer.
+//
+// Returns a pointer to the existing process map, or a pointer to a
+// newly created process map if CAN_CREATE is non-zero.
+//----------------------------------------------------------------------
+static ProcessMap*
+GetProcessMap(bool can_create)
+{
+ static ProcessMap* g_process_map_ptr = NULL;
+
+ if (can_create && g_process_map_ptr == NULL)
+ {
+ static pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER;
+ PTHREAD_MUTEX_LOCKER (locker, &g_process_map_mutex);
+ if (g_process_map_ptr == NULL)
+ g_process_map_ptr = new ProcessMap;
+ }
+ return g_process_map_ptr;
+}
+
+//----------------------------------------------------------------------
+// Add PID to the shared process pointer map.
+//
+// Return non-zero value if we succeed in adding the process to the map.
+// The only time this should fail is if we run out of memory and can't
+// allocate a ProcessMap.
+//----------------------------------------------------------------------
+static nub_bool_t
+AddProcessToMap (nub_process_t pid, MachProcessSP& procSP)
+{
+ ProcessMap* process_map = GetProcessMap(true);
+ if (process_map)
+ {
+ process_map->insert(std::make_pair(pid, procSP));
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Remove the shared pointer for PID from the process map.
+//
+// Returns the number of items removed from the process map.
+//----------------------------------------------------------------------
+static size_t
+RemoveProcessFromMap (nub_process_t pid)
+{
+ ProcessMap* process_map = GetProcessMap(false);
+ if (process_map)
+ {
+ return process_map->erase(pid);
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Get the shared pointer for PID from the existing process map.
+//
+// Returns true if we successfully find a shared pointer to a
+// MachProcess object.
+//----------------------------------------------------------------------
+static nub_bool_t
+GetProcessSP (nub_process_t pid, MachProcessSP& procSP)
+{
+ ProcessMap* process_map = GetProcessMap(false);
+ if (process_map != NULL)
+ {
+ ProcessMapIter pos = process_map->find(pid);
+ if (pos != process_map->end())
+ {
+ procSP = pos->second;
+ return true;
+ }
+ }
+ procSP.reset();
+ return false;
+}
+
+
+static void *
+waitpid_thread (void *arg)
+{
+ const pid_t pid = (pid_t)(intptr_t)arg;
+ int status;
+ while (1)
+ {
+ pid_t child_pid = waitpid(pid, &status, 0);
+ DNBLogThreadedIf(LOG_PROCESS, "waitpid_process_thread (): waitpid (pid = %i, &status, 0) => %i, status = %i, errno = %i", pid, child_pid, status, errno);
+
+ if (child_pid < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ break;
+ }
+ else
+ {
+ if (WIFSTOPPED(status))
+ {
+ continue;
+ }
+ else// if (WIFEXITED(status) || WIFSIGNALED(status))
+ {
+ DNBLogThreadedIf(LOG_PROCESS, "waitpid_process_thread (): setting exit status for pid = %i to %i", child_pid, status);
+ DNBProcessSetExitStatus (child_pid, status);
+ return NULL;
+ }
+ }
+ }
+
+ // We should never exit as long as our child process is alive, so if we
+ // do something else went wrong and we should exit...
+ DNBLogThreadedIf(LOG_PROCESS, "waitpid_process_thread (): main loop exited, setting exit status to an invalid value (-1) for pid %i", pid);
+ DNBProcessSetExitStatus (pid, -1);
+ return NULL;
+}
+
+static bool
+spawn_waitpid_thread (pid_t pid)
+{
+ pthread_t thread = THREAD_NULL;
+ ::pthread_create (&thread, NULL, waitpid_thread, (void *)(intptr_t)pid);
+ if (thread != THREAD_NULL)
+ {
+ ::pthread_detach (thread);
+ return true;
+ }
+ return false;
+}
+
+nub_process_t
+DNBProcessLaunch (const char *path,
+ char const *argv[],
+ const char *envp[],
+ const char *stdio_path,
+ nub_launch_flavor_t launch_flavor,
+ char *err_str,
+ size_t err_len)
+{
+ DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv = %p, envp = %p, launch_flavor = %u, err = %p, err_len = %zu) called...", __FUNCTION__, path, argv, envp, launch_flavor, err_str, err_len);
+
+ if (err_str && err_len > 0)
+ err_str[0] = '\0';
+ struct stat path_stat;
+ if (::stat(path, &path_stat) == -1)
+ {
+ char stat_error[256];
+ ::strerror_r (errno, stat_error, sizeof(stat_error));
+ snprintf(err_str, err_len, "%s (%s)", stat_error, path);
+ return INVALID_NUB_PROCESS;
+ }
+
+ MachProcessSP processSP (new MachProcess);
+ if (processSP.get())
+ {
+ DNBError launch_err;
+ pid_t pid = processSP->LaunchForDebug(path, argv, envp, stdio_path, launch_flavor, launch_err);
+ if (err_str)
+ {
+ *err_str = '\0';
+ if (launch_err.Fail())
+ {
+ const char *launch_err_str = launch_err.AsString();
+ if (launch_err_str)
+ {
+ strncpy(err_str, launch_err_str, err_len-1);
+ err_str[err_len-1] = '\0'; // Make sure the error string is terminated
+ }
+ }
+ }
+
+ DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) new pid is %d...", pid);
+
+ if (pid != INVALID_NUB_PROCESS)
+ {
+ // Spawn a thread to reap our child inferior process...
+ spawn_waitpid_thread (pid);
+
+ if (processSP->Task().TaskPortForProcessID (launch_err) == TASK_NULL)
+ {
+ // We failed to get the task for our process ID which is bad.
+ if (err_str && err_len > 0)
+ {
+ if (launch_err.AsString())
+ {
+ ::snprintf (err_str, err_len, "failed to get the task for process %i (%s)", pid, launch_err.AsString());
+ }
+ else
+ {
+ ::snprintf (err_str, err_len, "failed to get the task for process %i", pid);
+ }
+ }
+ }
+ else
+ {
+ assert(AddProcessToMap(pid, processSP));
+ return pid;
+ }
+ }
+ }
+ return INVALID_NUB_PROCESS;
+}
+
+nub_process_t
+DNBProcessAttachByName (const char *name, struct timespec *timeout, char *err_str, size_t err_len)
+{
+ if (err_str && err_len > 0)
+ err_str[0] = '\0';
+ std::vector<struct kinfo_proc> matching_proc_infos;
+ size_t num_matching_proc_infos = GetAllInfosMatchingName(name, matching_proc_infos);
+ if (num_matching_proc_infos == 0)
+ {
+ DNBLogError ("error: no processes match '%s'\n", name);
+ return INVALID_NUB_PROCESS;
+ }
+ else if (num_matching_proc_infos > 1)
+ {
+ DNBLogError ("error: %u processes match '%s':\n", num_matching_proc_infos, name);
+ size_t i;
+ for (i=0; i<num_matching_proc_infos; ++i)
+ DNBLogError ("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid, matching_proc_infos[i].kp_proc.p_comm);
+ return INVALID_NUB_PROCESS;
+ }
+ else
+ {
+ return DNBProcessAttach (matching_proc_infos[0].kp_proc.p_pid, timeout, err_str, err_len);
+ }
+}
+
+nub_process_t
+DNBProcessAttach (nub_process_t attach_pid, struct timespec *timeout, char *err_str, size_t err_len)
+{
+ if (err_str && err_len > 0)
+ err_str[0] = '\0';
+
+ pid_t pid;
+ MachProcessSP processSP(new MachProcess);
+ if (processSP.get())
+ {
+ DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...", attach_pid);
+ pid = processSP->AttachForDebug (attach_pid, err_str, err_len);
+
+ if (pid != INVALID_NUB_PROCESS)
+ {
+ assert(AddProcessToMap(pid, processSP));
+ spawn_waitpid_thread(pid);
+ }
+ }
+
+ while (pid != INVALID_NUB_PROCESS)
+ {
+ // Wait for process to start up and hit entry point
+ DNBLogThreadedIf (LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged "
+ "| eEventProcessStoppedStateChanged, true, INFINITE)...",
+ __FUNCTION__, pid);
+ nub_event_t set_events = DNBProcessWaitForEvents (pid,
+ eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged,
+ true, timeout);
+ DNBLogThreadedIf (LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged "
+ "| eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x",
+ __FUNCTION__, pid, set_events);
+
+ if (set_events == 0)
+ {
+ if (err_str && err_len > 0)
+ snprintf(err_str, err_len, "operation timed out");
+ pid = INVALID_NUB_PROCESS;
+ }
+ else
+ {
+ if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
+ {
+ nub_state_t pid_state = DNBProcessGetState (pid);
+ DNBLogThreadedIf (LOG_PROCESS, "%s process %4.4x state changed (eEventProcessStateChanged): %s",
+ __FUNCTION__, pid, DNBStateAsString(pid_state));
+
+ switch (pid_state)
+ {
+ default:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateSuspended:
+ break; // Ignore
+
+ case eStateRunning:
+ case eStateStepping:
+ // Still waiting to stop at entry point...
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ return pid;
+ case eStateDetached:
+ case eStateExited:
+ if (err_str && err_len > 0)
+ snprintf(err_str, err_len, "process exited");
+ return INVALID_NUB_PROCESS;
+ }
+ }
+
+ DNBProcessResetEvents(pid, set_events);
+ }
+ }
+
+ return INVALID_NUB_PROCESS;
+}
+
+static size_t
+GetAllInfos(std::vector<struct kinfo_proc>& proc_infos)
+{
+ size_t size;
+ int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
+ u_int namelen = sizeof(name)/sizeof(int);
+ int err;
+
+ // Try to find out how many processes are around so we can
+ // size the buffer appropriately. sysctl's man page specifically suggests
+ // this approach, and says it returns a bit larger size than needed to
+ // handle any new processes created between then and now.
+
+ err = ::sysctl (name, namelen, NULL, &size, NULL, 0);
+
+ if ((err < 0) && (err != ENOMEM))
+ {
+ proc_infos.clear();
+ perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)");
+ return 0;
+ }
+
+
+ // Increase the size of the buffer by a few processes in case more have
+ // been spawned
+ proc_infos.resize (size / sizeof(struct kinfo_proc));
+ size = proc_infos.size() * sizeof(struct kinfo_proc); // Make sure we don't exceed our resize...
+ err = ::sysctl (name, namelen, &proc_infos[0], &size, NULL, 0);
+ if (err < 0)
+ {
+ proc_infos.clear();
+ return 0;
+ }
+
+ // Trim down our array to fit what we actually got back
+ proc_infos.resize(size / sizeof(struct kinfo_proc));
+ return proc_infos.size();
+}
+
+
+static size_t
+GetAllInfosMatchingName(const char *full_process_name, std::vector<struct kinfo_proc>& matching_proc_infos)
+{
+
+ matching_proc_infos.clear();
+ if (full_process_name && full_process_name[0])
+ {
+ // We only get the process name, not the full path, from the proc_info. So just take the
+ // base name of the process name...
+ const char *process_name;
+ process_name = strrchr (full_process_name, '/');
+ if (process_name == NULL)
+ process_name = full_process_name;
+ else
+ process_name++;
+
+ std::vector<struct kinfo_proc> proc_infos;
+ const size_t num_proc_infos = GetAllInfos(proc_infos);
+ if (num_proc_infos > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_proc_infos; i++)
+ {
+ // Skip zombie processes and processes with unset status
+ if (proc_infos[i].kp_proc.p_stat == 0 || proc_infos[i].kp_proc.p_stat == SZOMB)
+ continue;
+
+ // Check for process by name. We only check the first MAXCOMLEN
+ // chars as that is all that kp_proc.p_comm holds.
+ if (::strncasecmp(proc_infos[i].kp_proc.p_comm, process_name, MAXCOMLEN) == 0)
+ {
+ // We found a matching process, add it to our list
+ matching_proc_infos.push_back(proc_infos[i]);
+ }
+ }
+ }
+ }
+ // return the newly added matches.
+ return matching_proc_infos.size();
+}
+
+nub_process_t
+DNBProcessAttachWait (const char *waitfor_process_name, nub_launch_flavor_t launch_flavor,
+ struct timespec *timeout_abstime, useconds_t waitfor_interval,
+ char *err_str, size_t err_len,
+ DNBShouldCancelCallback should_cancel_callback,
+ void *callback_data)
+{
+ DNBError prepare_error;
+ std::vector<struct kinfo_proc> exclude_proc_infos;
+ size_t num_exclude_proc_infos;
+
+ // If the PrepareForAttach returns a valid token, use MachProcess to check
+ // for the process, otherwise scan the process table.
+
+ const void *attach_token = MachProcess::PrepareForAttach (waitfor_process_name, launch_flavor, true, prepare_error);
+
+ if (prepare_error.Fail())
+ {
+ DNBLogError ("Error in PrepareForAttach: %s", prepare_error.AsString());
+ return INVALID_NUB_PROCESS;
+ }
+
+ if (attach_token == NULL)
+ num_exclude_proc_infos = GetAllInfosMatchingName (waitfor_process_name, exclude_proc_infos);
+
+ DNBLogThreadedIf (LOG_PROCESS, "Waiting for '%s' to appear...\n", waitfor_process_name);
+
+ // Loop and try to find the process by name
+ nub_process_t waitfor_pid = INVALID_NUB_PROCESS;
+
+ while (waitfor_pid == INVALID_NUB_PROCESS)
+ {
+ if (attach_token != NULL)
+ {
+ nub_process_t pid;
+ pid = MachProcess::CheckForProcess(attach_token);
+ if (pid != INVALID_NUB_PROCESS)
+ {
+ waitfor_pid = pid;
+ break;
+ }
+ }
+ else
+ {
+
+ // Get the current process list, and check for matches that
+ // aren't in our original list. If anyone wants to attach
+ // to an existing process by name, they should do it with
+ // --attach=PROCNAME. Else we will wait for the first matching
+ // process that wasn't in our exclusion list.
+ std::vector<struct kinfo_proc> proc_infos;
+ const size_t num_proc_infos = GetAllInfosMatchingName (waitfor_process_name, proc_infos);
+ for (size_t i=0; i<num_proc_infos; i++)
+ {
+ nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid;
+ for (size_t j=0; j<num_exclude_proc_infos; j++)
+ {
+ if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid)
+ {
+ // This process was in our exclusion list, don't use it.
+ curr_pid = INVALID_NUB_PROCESS;
+ break;
+ }
+ }
+
+ // If we didn't find CURR_PID in our exclusion list, then use it.
+ if (curr_pid != INVALID_NUB_PROCESS)
+ {
+ // We found our process!
+ waitfor_pid = curr_pid;
+ break;
+ }
+ }
+ }
+
+ // If we haven't found our process yet, check for a timeout
+ // and then sleep for a bit until we poll again.
+ if (waitfor_pid == INVALID_NUB_PROCESS)
+ {
+ if (timeout_abstime != NULL)
+ {
+ // Check to see if we have a waitfor-duration option that
+ // has timed out?
+ if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime))
+ {
+ if (err_str && err_len > 0)
+ snprintf(err_str, err_len, "operation timed out");
+ DNBLogError ("error: waiting for process '%s' timed out.\n", waitfor_process_name);
+ return INVALID_NUB_PROCESS;
+ }
+ }
+
+ // Call the should cancel callback as well...
+
+ if (should_cancel_callback != NULL
+ && should_cancel_callback (callback_data))
+ {
+ DNBLogThreadedIf (LOG_PROCESS, "DNBProcessAttachWait cancelled by should_cancel callback.");
+ waitfor_pid = INVALID_NUB_PROCESS;
+ break;
+ }
+
+ ::usleep (waitfor_interval); // Sleep for WAITFOR_INTERVAL, then poll again
+ }
+ }
+
+ if (waitfor_pid != INVALID_NUB_PROCESS)
+ {
+ DNBLogThreadedIf (LOG_PROCESS, "Attaching to %s with pid %i...\n", waitfor_process_name, waitfor_pid);
+ waitfor_pid = DNBProcessAttach (waitfor_pid, timeout_abstime, err_str, err_len);
+ }
+
+ bool success = waitfor_pid != INVALID_NUB_PROCESS;
+ MachProcess::CleanupAfterAttach (attach_token, success, prepare_error);
+
+ return waitfor_pid;
+}
+
+nub_bool_t
+DNBProcessDetach (nub_process_t pid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->Detach();
+ }
+ return false;
+}
+
+nub_bool_t
+DNBProcessKill (nub_process_t pid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->Kill ();
+ }
+ return false;
+}
+
+nub_bool_t
+DNBProcessSignal (nub_process_t pid, int signal)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->Signal (signal);
+ }
+ return false;
+}
+
+
+nub_bool_t
+DNBProcessIsAlive (nub_process_t pid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return MachTask::IsValid (procSP->Task().TaskPort());
+ }
+ return eStateInvalid;
+}
+
+//----------------------------------------------------------------------
+// Process and Thread state information
+//----------------------------------------------------------------------
+nub_state_t
+DNBProcessGetState (nub_process_t pid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->GetState();
+ }
+ return eStateInvalid;
+}
+
+//----------------------------------------------------------------------
+// Process and Thread state information
+//----------------------------------------------------------------------
+nub_bool_t
+DNBProcessGetExitStatus (nub_process_t pid, int* status)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->GetExitStatus(status);
+ }
+ return false;
+}
+
+nub_bool_t
+DNBProcessSetExitStatus (nub_process_t pid, int status)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ procSP->SetExitStatus(status);
+ return true;
+ }
+ return false;
+}
+
+
+const char *
+DNBThreadGetName (nub_process_t pid, nub_thread_t tid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->ThreadGetName(tid);
+ return NULL;
+}
+
+
+nub_bool_t
+DNBThreadGetIdentifierInfo (nub_process_t pid, nub_thread_t tid, thread_identifier_info_data_t *ident_info)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info);
+ return false;
+}
+
+nub_state_t
+DNBThreadGetState (nub_process_t pid, nub_thread_t tid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->ThreadGetState(tid);
+ }
+ return eStateInvalid;
+}
+
+const char *
+DNBStateAsString(nub_state_t state)
+{
+ switch (state)
+ {
+ case eStateUnloaded: return "Unloaded";
+ 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";
+ }
+ return "nub_state_t ???";
+}
+
+const char *
+DNBProcessGetExecutablePath (nub_process_t pid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->Path();
+ }
+ return NULL;
+}
+
+nub_size_t
+DNBProcessGetArgumentCount (nub_process_t pid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->ArgumentCount();
+ }
+ return 0;
+}
+
+const char *
+DNBProcessGetArgumentAtIndex (nub_process_t pid, nub_size_t idx)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->ArgumentAtIndex (idx);
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Execution control
+//----------------------------------------------------------------------
+nub_bool_t
+DNBProcessResume (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions)
+{
+ DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ DNBThreadResumeActions thread_actions (actions, num_actions);
+
+ // Below we add a default thread plan just in case one wasn't
+ // provided so all threads always know what they were supposed to do
+ if (thread_actions.IsEmpty())
+ {
+ // No thread plans were given, so the default it to run all threads
+ thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, 0);
+ }
+ else
+ {
+ // Some thread plans were given which means anything that wasn't
+ // specified should remain stopped.
+ thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0);
+ }
+ return procSP->Resume (thread_actions);
+ }
+ return false;
+}
+
+nub_bool_t
+DNBProcessHalt (nub_process_t pid)
+{
+ DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->Signal (SIGSTOP);
+ return false;
+}
+//
+//nub_bool_t
+//DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step)
+//{
+// DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)", __FUNCTION__, pid, tid, (uint32_t)step);
+// MachProcessSP procSP;
+// if (GetProcessSP (pid, procSP))
+// {
+// return procSP->Resume(tid, step, 0);
+// }
+// return false;
+//}
+//
+//nub_bool_t
+//DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t step, int signal)
+//{
+// DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u, signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal);
+// MachProcessSP procSP;
+// if (GetProcessSP (pid, procSP))
+// {
+// return procSP->Resume(tid, step, signal);
+// }
+// return false;
+//}
+
+nub_event_t
+DNBProcessWaitForEvents (nub_process_t pid, nub_event_t event_mask, bool wait_for_set, struct timespec* timeout)
+{
+ nub_event_t result = 0;
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ if (wait_for_set)
+ result = procSP->Events().WaitForSetEvents(event_mask, timeout);
+ else
+ result = procSP->Events().WaitForEventsToReset(event_mask, timeout);
+ }
+ return result;
+}
+
+void
+DNBProcessResetEvents (nub_process_t pid, nub_event_t event_mask)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ procSP->Events().ResetEvents(event_mask);
+}
+
+void
+DNBProcessInterruptEvents (nub_process_t pid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ procSP->Events().SetEvents(eEventProcessAsyncInterrupt);
+}
+
+
+// Breakpoints
+nub_break_t
+DNBBreakpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, nub_bool_t hardware)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->CreateBreakpoint(addr, size, hardware, THREAD_NULL);
+ }
+ return INVALID_NUB_BREAK_ID;
+}
+
+nub_bool_t
+DNBBreakpointClear (nub_process_t pid, nub_break_t breakID)
+{
+ if (NUB_BREAK_ID_IS_VALID(breakID))
+ {
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->DisableBreakpoint(breakID, true);
+ }
+ }
+ return false; // Failed
+}
+
+nub_ssize_t
+DNBBreakpointGetHitCount (nub_process_t pid, nub_break_t breakID)
+{
+ if (NUB_BREAK_ID_IS_VALID(breakID))
+ {
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ DNBBreakpoint *bp = procSP->Breakpoints().FindByID(breakID);
+ if (bp)
+ return bp->GetHitCount();
+ }
+ }
+ return 0;
+}
+
+nub_ssize_t
+DNBBreakpointGetIgnoreCount (nub_process_t pid, nub_break_t breakID)
+{
+ if (NUB_BREAK_ID_IS_VALID(breakID))
+ {
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ DNBBreakpoint *bp = procSP->Breakpoints().FindByID(breakID);
+ if (bp)
+ return bp->GetIgnoreCount();
+ }
+ }
+ return 0;
+}
+
+nub_bool_t
+DNBBreakpointSetIgnoreCount (nub_process_t pid, nub_break_t breakID, nub_size_t ignore_count)
+{
+ if (NUB_BREAK_ID_IS_VALID(breakID))
+ {
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ DNBBreakpoint *bp = procSP->Breakpoints().FindByID(breakID);
+ if (bp)
+ {
+ bp->SetIgnoreCount(ignore_count);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// Set the callback function for a given breakpoint. The callback function will
+// get called as soon as the breakpoint is hit. The function will be called
+// with the process ID, thread ID, breakpoint ID and the baton, and can return
+//
+nub_bool_t
+DNBBreakpointSetCallback (nub_process_t pid, nub_break_t breakID, DNBCallbackBreakpointHit callback, void *baton)
+{
+ if (NUB_BREAK_ID_IS_VALID(breakID))
+ {
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ DNBBreakpoint *bp = procSP->Breakpoints().FindByID(breakID);
+ if (bp)
+ {
+ bp->SetCallback(callback, baton);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Dump the breakpoints stats for process PID for a breakpoint by ID.
+//----------------------------------------------------------------------
+void
+DNBBreakpointPrint (nub_process_t pid, nub_break_t breakID)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ procSP->DumpBreakpoint(breakID);
+}
+
+//----------------------------------------------------------------------
+// Watchpoints
+//----------------------------------------------------------------------
+nub_watch_t
+DNBWatchpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, uint32_t watch_flags, nub_bool_t hardware)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->CreateWatchpoint(addr, size, watch_flags, hardware, THREAD_NULL);
+ }
+ return INVALID_NUB_BREAK_ID;
+}
+
+nub_bool_t
+DNBWatchpointClear (nub_process_t pid, nub_watch_t watchID)
+{
+ if (NUB_BREAK_ID_IS_VALID(watchID))
+ {
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->DisableWatchpoint(watchID, true);
+ }
+ }
+ return false; // Failed
+}
+
+nub_ssize_t
+DNBWatchpointGetHitCount (nub_process_t pid, nub_watch_t watchID)
+{
+ if (NUB_BREAK_ID_IS_VALID(watchID))
+ {
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ DNBBreakpoint *bp = procSP->Watchpoints().FindByID(watchID);
+ if (bp)
+ return bp->GetHitCount();
+ }
+ }
+ return 0;
+}
+
+nub_ssize_t
+DNBWatchpointGetIgnoreCount (nub_process_t pid, nub_watch_t watchID)
+{
+ if (NUB_BREAK_ID_IS_VALID(watchID))
+ {
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ DNBBreakpoint *bp = procSP->Watchpoints().FindByID(watchID);
+ if (bp)
+ return bp->GetIgnoreCount();
+ }
+ }
+ return 0;
+}
+
+nub_bool_t
+DNBWatchpointSetIgnoreCount (nub_process_t pid, nub_watch_t watchID, nub_size_t ignore_count)
+{
+ if (NUB_BREAK_ID_IS_VALID(watchID))
+ {
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ DNBBreakpoint *bp = procSP->Watchpoints().FindByID(watchID);
+ if (bp)
+ {
+ bp->SetIgnoreCount(ignore_count);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// Set the callback function for a given watchpoint. The callback function will
+// get called as soon as the watchpoint is hit. The function will be called
+// with the process ID, thread ID, watchpoint ID and the baton, and can return
+//
+nub_bool_t
+DNBWatchpointSetCallback (nub_process_t pid, nub_watch_t watchID, DNBCallbackBreakpointHit callback, void *baton)
+{
+ if (NUB_BREAK_ID_IS_VALID(watchID))
+ {
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ DNBBreakpoint *bp = procSP->Watchpoints().FindByID(watchID);
+ if (bp)
+ {
+ bp->SetCallback(callback, baton);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Dump the watchpoints stats for process PID for a watchpoint by ID.
+//----------------------------------------------------------------------
+void
+DNBWatchpointPrint (nub_process_t pid, nub_watch_t watchID)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ procSP->DumpWatchpoint(watchID);
+}
+
+//----------------------------------------------------------------------
+// Read memory in the address space of process PID. This call will take
+// care of setting and restoring permissions and breaking up the memory
+// read into multiple chunks as required.
+//
+// RETURNS: number of bytes actually read
+//----------------------------------------------------------------------
+nub_size_t
+DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->ReadMemory(addr, size, buf);
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Write memory to the address space of process PID. This call will take
+// care of setting and restoring permissions and breaking up the memory
+// write into multiple chunks as required.
+//
+// RETURNS: number of bytes actually written
+//----------------------------------------------------------------------
+nub_size_t
+DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->WriteMemory(addr, size, buf);
+ return 0;
+}
+
+nub_addr_t
+DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->Task().AllocateMemory (size, permissions);
+ return 0;
+}
+
+nub_bool_t
+DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->Task().DeallocateMemory (addr);
+ return 0;
+}
+
+
+//----------------------------------------------------------------------
+// Formatted output that uses memory and registers from process and
+// thread in place of arguments.
+//----------------------------------------------------------------------
+nub_size_t
+DNBPrintf (nub_process_t pid, nub_thread_t tid, nub_addr_t base_addr, FILE *file, const char *format)
+{
+ if (file == NULL)
+ return 0;
+ enum printf_flags
+ {
+ alternate_form = (1 << 0),
+ zero_padding = (1 << 1),
+ negative_field_width = (1 << 2),
+ blank_space = (1 << 3),
+ show_sign = (1 << 4),
+ show_thousands_separator= (1 << 5),
+ };
+
+ enum printf_length_modifiers
+ {
+ length_mod_h = (1 << 0),
+ length_mod_hh = (1 << 1),
+ length_mod_l = (1 << 2),
+ length_mod_ll = (1 << 3),
+ length_mod_L = (1 << 4),
+ length_mod_j = (1 << 5),
+ length_mod_t = (1 << 6),
+ length_mod_z = (1 << 7),
+ length_mod_q = (1 << 8),
+ };
+
+ nub_addr_t addr = base_addr;
+ char *end_format = (char*)format + strlen(format);
+ char *end = NULL; // For strtoXXXX calls;
+ std::basic_string<uint8_t> buf;
+ nub_size_t total_bytes_read = 0;
+ DNBDataRef data;
+ const char *f;
+ for (f = format; *f != '\0' && f < end_format; f++)
+ {
+ char ch = *f;
+ switch (ch)
+ {
+ case '%':
+ {
+ f++; // Skip the '%' character
+ int min_field_width = 0;
+ int precision = 0;
+ uint32_t flags = 0;
+ uint32_t length_modifiers = 0;
+ uint32_t byte_size = 0;
+ uint32_t actual_byte_size = 0;
+ bool is_string = false;
+ bool is_register = false;
+ DNBRegisterValue register_value;
+ int64_t register_offset = 0;
+ nub_addr_t register_addr = INVALID_NUB_ADDRESS;
+
+ // Create the format string to use for this conversion specification
+ // so we can remove and mprintf specific flags and formatters.
+ std::string fprintf_format("%");
+
+ // Decode any flags
+ switch (*f)
+ {
+ case '#': fprintf_format += *f++; flags |= alternate_form; break;
+ case '0': fprintf_format += *f++; flags |= zero_padding; break;
+ case '-': fprintf_format += *f++; flags |= negative_field_width; break;
+ case ' ': fprintf_format += *f++; flags |= blank_space; break;
+ case '+': fprintf_format += *f++; flags |= show_sign; break;
+ case ',': fprintf_format += *f++; flags |= show_thousands_separator;break;
+ case '{':
+ case '[':
+ {
+ // We have a register name specification that can take two forms:
+ // ${regname} or ${regname+offset}
+ // The action is to read the register value and add the signed offset
+ // (if any) and use that as the value to format.
+ // $[regname] or $[regname+offset]
+ // The action is to read the register value and add the signed offset
+ // (if any) and use the result as an address to dereference. The size
+ // of what is dereferenced is specified by the actual byte size that
+ // follows the minimum field width and precision (see comments below).
+ switch (*f)
+ {
+ case '{':
+ case '[':
+ {
+ char open_scope_ch = *f;
+ f++;
+ const char *reg_name = f;
+ size_t reg_name_length = strcspn(f, "+-}]");
+ if (reg_name_length > 0)
+ {
+ std::string register_name(reg_name, reg_name_length);
+ f += reg_name_length;
+ register_offset = strtoll(f, &end, 0);
+ if (f < end)
+ f = end;
+ if ((open_scope_ch == '{' && *f != '}') || (open_scope_ch == '[' && *f != ']'))
+ {
+ fprintf(file, "error: Invalid register format string. Valid formats are %%{regname} or %%{regname+offset}, %%[regname] or %%[regname+offset]\n");
+ return total_bytes_read;
+ }
+ else
+ {
+ f++;
+ if (DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, register_name.c_str(), &register_value))
+ {
+ // Set the address to dereference using the register value plus the offset
+ switch (register_value.info.size)
+ {
+ default:
+ case 0:
+ fprintf (file, "error: unsupported register size of %u.\n", register_value.info.size);
+ return total_bytes_read;
+
+ case 1: register_addr = register_value.value.uint8 + register_offset; break;
+ case 2: register_addr = register_value.value.uint16 + register_offset; break;
+ case 4: register_addr = register_value.value.uint32 + register_offset; break;
+ case 8: register_addr = register_value.value.uint64 + register_offset; break;
+ case 16:
+ if (open_scope_ch == '[')
+ {
+ fprintf (file, "error: register size (%u) too large for address.\n", register_value.info.size);
+ return total_bytes_read;
+ }
+ break;
+ }
+
+ if (open_scope_ch == '{')
+ {
+ byte_size = register_value.info.size;
+ is_register = true; // value is in a register
+
+ }
+ else
+ {
+ addr = register_addr; // Use register value and offset as the address
+ }
+ }
+ else
+ {
+ fprintf(file, "error: unable to read register '%s' for process %#.4x and thread %#.4x\n", register_name.c_str(), pid, tid);
+ return total_bytes_read;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ fprintf(file, "error: %%$ must be followed by (regname + n) or [regname + n]\n");
+ return total_bytes_read;
+ }
+ }
+ break;
+ }
+
+ // Check for a minimum field width
+ if (isdigit(*f))
+ {
+ min_field_width = strtoul(f, &end, 10);
+ if (end > f)
+ {
+ fprintf_format.append(f, end - f);
+ f = end;
+ }
+ }
+
+
+ // Check for a precision
+ if (*f == '.')
+ {
+ f++;
+ if (isdigit(*f))
+ {
+ fprintf_format += '.';
+ precision = strtoul(f, &end, 10);
+ if (end > f)
+ {
+ fprintf_format.append(f, end - f);
+ f = end;
+ }
+ }
+ }
+
+
+ // mprintf specific: read the optional actual byte size (abs)
+ // after the standard minimum field width (mfw) and precision (prec).
+ // Standard printf calls you can have "mfw.prec" or ".prec", but
+ // mprintf can have "mfw.prec.abs", ".prec.abs" or "..abs". This is nice
+ // for strings that may be in a fixed size buffer, but may not use all bytes
+ // in that buffer for printable characters.
+ if (*f == '.')
+ {
+ f++;
+ actual_byte_size = strtoul(f, &end, 10);
+ if (end > f)
+ {
+ byte_size = actual_byte_size;
+ f = end;
+ }
+ }
+
+ // Decode the length modifiers
+ switch (*f)
+ {
+ case 'h': // h and hh length modifiers
+ fprintf_format += *f++;
+ length_modifiers |= length_mod_h;
+ if (*f == 'h')
+ {
+ fprintf_format += *f++;
+ length_modifiers |= length_mod_hh;
+ }
+ break;
+
+ case 'l': // l and ll length modifiers
+ fprintf_format += *f++;
+ length_modifiers |= length_mod_l;
+ if (*f == 'h')
+ {
+ fprintf_format += *f++;
+ length_modifiers |= length_mod_ll;
+ }
+ break;
+
+ case 'L': fprintf_format += *f++; length_modifiers |= length_mod_L; break;
+ case 'j': fprintf_format += *f++; length_modifiers |= length_mod_j; break;
+ case 't': fprintf_format += *f++; length_modifiers |= length_mod_t; break;
+ case 'z': fprintf_format += *f++; length_modifiers |= length_mod_z; break;
+ case 'q': fprintf_format += *f++; length_modifiers |= length_mod_q; break;
+ }
+
+ // Decode the conversion specifier
+ switch (*f)
+ {
+ case '_':
+ // mprintf specific format items
+ {
+ ++f; // Skip the '_' character
+ switch (*f)
+ {
+ case 'a': // Print the current address
+ ++f;
+ fprintf_format += "ll";
+ fprintf_format += *f; // actual format to show address with folows the 'a' ("%_ax")
+ fprintf (file, fprintf_format.c_str(), addr);
+ break;
+ case 'o': // offset from base address
+ ++f;
+ fprintf_format += "ll";
+ fprintf_format += *f; // actual format to show address with folows the 'a' ("%_ox")
+ fprintf(file, fprintf_format.c_str(), addr - base_addr);
+ break;
+ default:
+ fprintf (file, "error: unsupported mprintf specific format character '%c'.\n", *f);
+ break;
+ }
+ continue;
+ }
+ break;
+
+ case 'D':
+ case 'O':
+ case 'U':
+ fprintf_format += *f;
+ if (byte_size == 0)
+ byte_size = sizeof(long int);
+ break;
+
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ fprintf_format += *f;
+ if (byte_size == 0)
+ {
+ if (length_modifiers & length_mod_hh)
+ byte_size = sizeof(char);
+ else if (length_modifiers & length_mod_h)
+ byte_size = sizeof(short);
+ if (length_modifiers & length_mod_ll)
+ byte_size = sizeof(long long);
+ else if (length_modifiers & length_mod_l)
+ byte_size = sizeof(long);
+ else
+ byte_size = sizeof(int);
+ }
+ break;
+
+ case 'a':
+ case 'A':
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ fprintf_format += *f;
+ if (byte_size == 0)
+ {
+ if (length_modifiers & length_mod_L)
+ byte_size = sizeof(long double);
+ else
+ byte_size = sizeof(double);
+ }
+ break;
+
+ case 'c':
+ if ((length_modifiers & length_mod_l) == 0)
+ {
+ fprintf_format += *f;
+ if (byte_size == 0)
+ byte_size = sizeof(char);
+ break;
+ }
+ // Fall through to 'C' modifier below...
+
+ case 'C':
+ fprintf_format += *f;
+ if (byte_size == 0)
+ byte_size = sizeof(wchar_t);
+ break;
+
+ case 's':
+ fprintf_format += *f;
+ if (is_register || byte_size == 0)
+ is_string = 1;
+ break;
+
+ case 'p':
+ fprintf_format += *f;
+ if (byte_size == 0)
+ byte_size = sizeof(void*);
+ break;
+ }
+
+ if (is_string)
+ {
+ std::string mem_string;
+ const size_t string_buf_len = 4;
+ char string_buf[string_buf_len+1];
+ char *string_buf_end = string_buf + string_buf_len;
+ string_buf[string_buf_len] = '\0';
+ nub_size_t bytes_read;
+ nub_addr_t str_addr = is_register ? register_addr : addr;
+ while ((bytes_read = DNBProcessMemoryRead(pid, str_addr, string_buf_len, &string_buf[0])) > 0)
+ {
+ // Did we get a NULL termination character yet?
+ if (strchr(string_buf, '\0') == string_buf_end)
+ {
+ // no NULL terminator yet, append as a std::string
+ mem_string.append(string_buf, string_buf_len);
+ str_addr += string_buf_len;
+ }
+ else
+ {
+ // yep
+ break;
+ }
+ }
+ // Append as a C-string so we don't get the extra NULL
+ // characters in the temp buffer (since it was resized)
+ mem_string += string_buf;
+ size_t mem_string_len = mem_string.size() + 1;
+ fprintf(file, fprintf_format.c_str(), mem_string.c_str());
+ if (mem_string_len > 0)
+ {
+ if (!is_register)
+ {
+ addr += mem_string_len;
+ total_bytes_read += mem_string_len;
+ }
+ }
+ else
+ return total_bytes_read;
+ }
+ else
+ if (byte_size > 0)
+ {
+ buf.resize(byte_size);
+ nub_size_t bytes_read = 0;
+ if (is_register)
+ bytes_read = register_value.info.size;
+ else
+ bytes_read = DNBProcessMemoryRead(pid, addr, buf.size(), &buf[0]);
+ if (bytes_read > 0)
+ {
+ if (!is_register)
+ total_bytes_read += bytes_read;
+
+ if (bytes_read == byte_size)
+ {
+ switch (*f)
+ {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'X':
+ case 'x':
+ case 'a':
+ case 'A':
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ case 'p':
+ case 'c':
+ case 'C':
+ {
+ if (is_register)
+ data.SetData(&register_value.value.v_uint8[0], register_value.info.size);
+ else
+ data.SetData(&buf[0], bytes_read);
+ DNBDataRef::offset_t data_offset = 0;
+ if (byte_size <= 4)
+ {
+ uint32_t u32 = data.GetMax32(&data_offset, byte_size);
+ // Show the actual byte width when displaying hex
+ fprintf(file, fprintf_format.c_str(), u32);
+ }
+ else if (byte_size <= 8)
+ {
+ uint64_t u64 = data.GetMax64(&data_offset, byte_size);
+ // Show the actual byte width when displaying hex
+ fprintf(file, fprintf_format.c_str(), u64);
+ }
+ else
+ {
+ fprintf(file, "error: integer size not supported, must be 8 bytes or less (%u bytes).\n", byte_size);
+ }
+ if (!is_register)
+ addr += byte_size;
+ }
+ break;
+
+ case 's':
+ fprintf(file, fprintf_format.c_str(), buf.c_str());
+ addr += byte_size;
+ break;
+
+ default:
+ fprintf(file, "error: unsupported conversion specifier '%c'.\n", *f);
+ break;
+ }
+ }
+ }
+ }
+ else
+ return total_bytes_read;
+ }
+ break;
+
+ case '\\':
+ {
+ f++;
+ switch (*f)
+ {
+ case 'e': ch = '\e'; break;
+ case 'a': ch = '\a'; break;
+ case 'b': ch = '\b'; break;
+ case 'f': ch = '\f'; break;
+ case 'n': ch = '\n'; break;
+ case 'r': ch = '\r'; break;
+ case 't': ch = '\t'; break;
+ case 'v': ch = '\v'; break;
+ case '\'': ch = '\''; break;
+ case '\\': ch = '\\'; break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ ch = strtoul(f, &end, 8);
+ f = end;
+ break;
+ default:
+ ch = *f;
+ break;
+ }
+ fputc(ch, file);
+ }
+ break;
+
+ default:
+ fputc(ch, file);
+ break;
+ }
+ }
+ return total_bytes_read;
+}
+
+
+//----------------------------------------------------------------------
+// Get the number of threads for the specified process.
+//----------------------------------------------------------------------
+nub_size_t
+DNBProcessGetNumThreads (nub_process_t pid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->GetNumThreads();
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Get the thread ID of the current thread.
+//----------------------------------------------------------------------
+nub_thread_t
+DNBProcessGetCurrentThread (nub_process_t pid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->GetCurrentThread();
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Change the current thread.
+//----------------------------------------------------------------------
+nub_thread_t
+DNBProcessSetCurrentThread (nub_process_t pid, nub_thread_t tid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->SetCurrentThread (tid);
+ return INVALID_NUB_THREAD;
+}
+
+
+//----------------------------------------------------------------------
+// Dump a string describing a thread's stop reason to the specified file
+// handle
+//----------------------------------------------------------------------
+nub_bool_t
+DNBThreadGetStopReason (nub_process_t pid, nub_thread_t tid, struct DNBThreadStopInfo *stop_info)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->GetThreadStoppedReason (tid, stop_info);
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Return string description for the specified thread.
+//
+// RETURNS: NULL if the thread isn't valid, else a NULL terminated C
+// string from a static buffer that must be copied prior to subsequent
+// calls.
+//----------------------------------------------------------------------
+const char *
+DNBThreadGetInfo (nub_process_t pid, nub_thread_t tid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->GetThreadInfo (tid);
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Get the thread ID given a thread index.
+//----------------------------------------------------------------------
+nub_thread_t
+DNBProcessGetThreadAtIndex (nub_process_t pid, size_t thread_idx)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->GetThreadAtIndex (thread_idx);
+ return INVALID_NUB_THREAD;
+}
+
+nub_addr_t
+DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid)
+{
+ MachProcessSP procSP;
+ DNBError err;
+ if (GetProcessSP (pid, procSP))
+ return procSP->Task().GetDYLDAllImageInfosAddress (err);
+ return INVALID_NUB_ADDRESS;
+}
+
+
+nub_bool_t
+DNBProcessSharedLibrariesUpdated(nub_process_t pid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ procSP->SharedLibrariesUpdated ();
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Get the current shared library information for a process. Only return
+// the shared libraries that have changed since the last shared library
+// state changed event if only_changed is non-zero.
+//----------------------------------------------------------------------
+nub_size_t
+DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, struct DNBExecutableImageInfo **image_infos)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->CopyImageInfos (image_infos, only_changed);
+
+ // If we have no process, then return NULL for the shared library info
+ // and zero for shared library count
+ *image_infos = NULL;
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Get the register set information for a specific thread.
+//----------------------------------------------------------------------
+const DNBRegisterSetInfo *
+DNBGetRegisterSetInfo (nub_size_t *num_reg_sets)
+{
+ return DNBArch::GetRegisterSetInfo (num_reg_sets);
+}
+
+
+//----------------------------------------------------------------------
+// Read a register value by register set and register index.
+//----------------------------------------------------------------------
+nub_bool_t
+DNBThreadGetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value)
+{
+ MachProcessSP procSP;
+ ::bzero (value, sizeof(DNBRegisterValue));
+ if (GetProcessSP (pid, procSP))
+ {
+ if (tid != INVALID_NUB_THREAD)
+ return procSP->GetRegisterValue (tid, set, reg, value);
+ }
+ return false;
+}
+
+nub_bool_t
+DNBThreadSetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value)
+{
+ if (tid != INVALID_NUB_THREAD)
+ {
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->SetRegisterValue (tid, set, reg, value);
+ }
+ return false;
+}
+
+nub_size_t
+DNBThreadGetRegisterContext (nub_process_t pid, nub_thread_t tid, void *buf, size_t buf_len)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ if (tid != INVALID_NUB_THREAD)
+ return procSP->GetThreadList().GetRegisterContext (tid, buf, buf_len);
+ }
+ ::bzero (buf, buf_len);
+ return 0;
+
+}
+
+nub_size_t
+DNBThreadSetRegisterContext (nub_process_t pid, nub_thread_t tid, const void *buf, size_t buf_len)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ if (tid != INVALID_NUB_THREAD)
+ return procSP->GetThreadList().SetRegisterContext (tid, buf, buf_len);
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Read a register value by name.
+//----------------------------------------------------------------------
+nub_bool_t
+DNBThreadGetRegisterValueByName (nub_process_t pid, nub_thread_t tid, uint32_t reg_set, const char *reg_name, DNBRegisterValue *value)
+{
+ MachProcessSP procSP;
+ ::bzero (value, sizeof(DNBRegisterValue));
+ if (GetProcessSP (pid, procSP))
+ {
+ const struct DNBRegisterSetInfo *set_info;
+ nub_size_t num_reg_sets = 0;
+ set_info = DNBGetRegisterSetInfo (&num_reg_sets);
+ if (set_info)
+ {
+ uint32_t set = reg_set;
+ uint32_t reg;
+ if (set == REGISTER_SET_ALL)
+ {
+ for (set = 1; set < num_reg_sets; ++set)
+ {
+ for (reg = 0; reg < set_info[set].num_registers; ++reg)
+ {
+ if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
+ return procSP->GetRegisterValue (tid, set, reg, value);
+ }
+ }
+ }
+ else
+ {
+ for (reg = 0; reg < set_info[set].num_registers; ++reg)
+ {
+ if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
+ return procSP->GetRegisterValue (tid, set, reg, value);
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+//----------------------------------------------------------------------
+// Read a register set and register number from the register name.
+//----------------------------------------------------------------------
+nub_bool_t
+DNBGetRegisterInfoByName (const char *reg_name, DNBRegisterInfo* info)
+{
+ const struct DNBRegisterSetInfo *set_info;
+ nub_size_t num_reg_sets = 0;
+ set_info = DNBGetRegisterSetInfo (&num_reg_sets);
+ if (set_info)
+ {
+ uint32_t set, reg;
+ for (set = 1; set < num_reg_sets; ++set)
+ {
+ for (reg = 0; reg < set_info[set].num_registers; ++reg)
+ {
+ if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
+ {
+ *info = set_info[set].registers[reg];
+ return true;
+ }
+ }
+ }
+
+ for (set = 1; set < num_reg_sets; ++set)
+ {
+ uint32_t reg;
+ for (reg = 0; reg < set_info[set].num_registers; ++reg)
+ {
+ if (set_info[set].registers[reg].alt == NULL)
+ continue;
+
+ if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0)
+ {
+ *info = set_info[set].registers[reg];
+ return true;
+ }
+ }
+ }
+ }
+
+ ::bzero (info, sizeof(DNBRegisterInfo));
+ return false;
+}
+
+
+//----------------------------------------------------------------------
+// Set the name to address callback function that this nub can use
+// for any name to address lookups that are needed.
+//----------------------------------------------------------------------
+nub_bool_t
+DNBProcessSetNameToAddressCallback (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ procSP->SetNameToAddressCallback (callback, baton);
+ return true;
+ }
+ return false;
+}
+
+
+//----------------------------------------------------------------------
+// Set the name to address callback function that this nub can use
+// for any name to address lookups that are needed.
+//----------------------------------------------------------------------
+nub_bool_t
+DNBProcessSetSharedLibraryInfoCallback (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void *baton)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ procSP->SetSharedLibraryInfoCallback (callback, baton);
+ return true;
+ }
+ return false;
+}
+
+nub_addr_t
+DNBProcessLookupAddress (nub_process_t pid, const char *name, const char *shlib)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->LookupSymbol (name, shlib);
+ }
+ return INVALID_NUB_ADDRESS;
+}
+
+
+nub_size_t
+DNBProcessGetAvailableSTDOUT (nub_process_t pid, char *buf, nub_size_t buf_size)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->GetAvailableSTDOUT (buf, buf_size);
+ return 0;
+}
+
+nub_size_t
+DNBProcessGetAvailableSTDERR (nub_process_t pid, char *buf, nub_size_t buf_size)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->GetAvailableSTDERR (buf, buf_size);
+ return 0;
+}
+
+nub_size_t
+DNBProcessGetStopCount (nub_process_t pid)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ return procSP->StopCount();
+ return 0;
+}
+
+nub_bool_t
+DNBResolveExecutablePath (const char *path, char *resolved_path, size_t resolved_path_size)
+{
+ if (path == NULL || path[0] == '\0')
+ return false;
+
+ char max_path[PATH_MAX];
+ std::string result;
+ CFString::GlobPath(path, result);
+
+ if (result.empty())
+ result = path;
+
+ if (realpath(path, max_path))
+ {
+ // Found the path relatively...
+ ::strncpy(resolved_path, max_path, resolved_path_size);
+ return strlen(resolved_path) + 1 < resolved_path_size;
+ }
+ else
+ {
+ // Not a relative path, check the PATH environment variable if the
+ const char *PATH = getenv("PATH");
+ if (PATH)
+ {
+ const char *curr_path_start = PATH;
+ const char *curr_path_end;
+ while (curr_path_start && *curr_path_start)
+ {
+ curr_path_end = strchr(curr_path_start, ':');
+ if (curr_path_end == NULL)
+ {
+ result.assign(curr_path_start);
+ curr_path_start = NULL;
+ }
+ else if (curr_path_end > curr_path_start)
+ {
+ size_t len = curr_path_end - curr_path_start;
+ result.assign(curr_path_start, len);
+ curr_path_start += len + 1;
+ }
+ else
+ break;
+
+ result += '/';
+ result += path;
+ struct stat s;
+ if (stat(result.c_str(), &s) == 0)
+ {
+ ::strncpy(resolved_path, result.c_str(), resolved_path_size);
+ return result.size() + 1 < resolved_path_size;
+ }
+ }
+ }
+ }
+ return false;
+}
+
diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h
new file mode 100644
index 00000000000..55a039e2699
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNB.h
@@ -0,0 +1,141 @@
+//===-- DNB.h ---------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 3/23/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DNB_h__
+#define __DNB_h__
+
+#include "DNBDefs.h"
+#include <mach/thread_info.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DNB_EXPORT __attribute__((visibility("default")))
+
+typedef bool (*DNBShouldCancelCallback) (void *);
+
+//----------------------------------------------------------------------
+// Process control
+//----------------------------------------------------------------------
+nub_process_t DNBProcessLaunch (const char *path, char const *argv[], const char *envp[], const char *stdio_path, nub_launch_flavor_t launch_flavor, char *err_str, size_t err_len) DNB_EXPORT;
+nub_process_t DNBProcessAttach (nub_process_t pid, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT;
+nub_process_t DNBProcessAttachByName (const char *name, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT;
+nub_process_t DNBProcessAttachWait (const char *wait_name, nub_launch_flavor_t launch_flavor, struct timespec *timeout, useconds_t interval, char *err_str, size_t err_len, DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL) DNB_EXPORT;
+// Resume a process with exact instructions on what to do with each thread:
+// - If no thread actions are supplied (actions is NULL or num_actions is zero),
+// then all threads are continued.
+// - If any thread actions are supplied, then each thread will do as it is told
+// by the action. A default actions for any threads that don't have an
+// explicit thread action can be made by making a thread action with a tid of
+// INVALID_NUB_THREAD. If there is no default action, those threads will
+// remain stopped.
+nub_bool_t DNBProcessResume (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions) DNB_EXPORT;
+nub_bool_t DNBProcessHalt (nub_process_t pid) DNB_EXPORT;
+nub_bool_t DNBProcessDetach (nub_process_t pid) DNB_EXPORT;
+nub_bool_t DNBProcessSignal (nub_process_t pid, int signal) DNB_EXPORT;
+nub_bool_t DNBProcessKill (nub_process_t pid) DNB_EXPORT;
+nub_size_t DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf) DNB_EXPORT;
+nub_size_t DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf) DNB_EXPORT;
+nub_addr_t DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions) DNB_EXPORT;
+nub_bool_t DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr) DNB_EXPORT;
+//----------------------------------------------------------------------
+// Process status
+//----------------------------------------------------------------------
+nub_bool_t DNBProcessIsAlive (nub_process_t pid) DNB_EXPORT;
+nub_state_t DNBProcessGetState (nub_process_t pid) DNB_EXPORT;
+nub_bool_t DNBProcessGetExitStatus (nub_process_t pid, int *status) DNB_EXPORT;
+nub_bool_t DNBProcessSetExitStatus (nub_process_t pid, int status) DNB_EXPORT;
+nub_size_t DNBProcessGetNumThreads (nub_process_t pid) DNB_EXPORT;
+nub_thread_t DNBProcessGetCurrentThread (nub_process_t pid) DNB_EXPORT;
+nub_thread_t DNBProcessSetCurrentThread (nub_process_t pid, nub_thread_t tid) DNB_EXPORT;
+nub_thread_t DNBProcessGetThreadAtIndex (nub_process_t pid, nub_size_t thread_idx) DNB_EXPORT;
+nub_addr_t DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid) DNB_EXPORT;
+nub_bool_t DNBProcessSharedLibrariesUpdated (nub_process_t pid) DNB_EXPORT;
+nub_size_t DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, DNBExecutableImageInfo **image_infos) DNB_EXPORT;
+nub_bool_t DNBProcessSetNameToAddressCallback (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton) DNB_EXPORT;
+nub_bool_t DNBProcessSetSharedLibraryInfoCallback (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void *baton) DNB_EXPORT;
+nub_addr_t DNBProcessLookupAddress (nub_process_t pid, const char *name, const char *shlib) DNB_EXPORT;
+nub_size_t DNBProcessGetAvailableSTDOUT (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT;
+nub_size_t DNBProcessGetAvailableSTDERR (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT;
+nub_size_t DNBProcessGetStopCount (nub_process_t pid) DNB_EXPORT;
+//----------------------------------------------------------------------
+// Process executable and arguments
+//----------------------------------------------------------------------
+const char * DNBProcessGetExecutablePath (nub_process_t pid) DNB_EXPORT;
+const char * DNBProcessGetArgumentAtIndex (nub_process_t pid, nub_size_t idx) DNB_EXPORT;
+nub_size_t DNBProcessGetArgumentCount (nub_process_t pid) DNB_EXPORT;
+
+//----------------------------------------------------------------------
+// Process events
+//----------------------------------------------------------------------
+nub_event_t DNBProcessWaitForEvents (nub_process_t pid, nub_event_t event_mask, bool wait_for_set, struct timespec* timeout) DNB_EXPORT;
+void DNBProcessResetEvents (nub_process_t pid, nub_event_t event_mask) DNB_EXPORT;
+void DNBProcessInterruptEvents (nub_process_t pid) DNB_EXPORT;
+
+//----------------------------------------------------------------------
+// Thread functions
+//----------------------------------------------------------------------
+const char * DNBThreadGetName (nub_process_t pid, nub_thread_t tid) DNB_EXPORT;
+nub_bool_t DNBThreadGetIdentifierInfo (nub_process_t pid, nub_thread_t tid, thread_identifier_info_data_t *ident_info) DNB_EXPORT;
+nub_state_t DNBThreadGetState (nub_process_t pid, nub_thread_t tid) DNB_EXPORT;
+nub_bool_t DNBThreadGetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value) DNB_EXPORT;
+nub_bool_t DNBThreadSetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value) DNB_EXPORT;
+nub_size_t DNBThreadGetRegisterContext (nub_process_t pid, nub_thread_t tid, void *buf, size_t buf_len) DNB_EXPORT;
+nub_size_t DNBThreadSetRegisterContext (nub_process_t pid, nub_thread_t tid, const void *buf, size_t buf_len) DNB_EXPORT;
+nub_bool_t DNBThreadGetRegisterValueByName (nub_process_t pid, nub_thread_t tid, uint32_t set, const char *name, DNBRegisterValue *value) DNB_EXPORT;
+nub_bool_t DNBThreadGetStopReason (nub_process_t pid, nub_thread_t tid, DNBThreadStopInfo *stop_info) DNB_EXPORT;
+const char * DNBThreadGetInfo (nub_process_t pid, nub_thread_t tid) DNB_EXPORT;
+//----------------------------------------------------------------------
+// Breakpoint functions
+//----------------------------------------------------------------------
+nub_break_t DNBBreakpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, nub_bool_t hardware) DNB_EXPORT;
+nub_bool_t DNBBreakpointClear (nub_process_t pid, nub_break_t breakID) DNB_EXPORT;
+nub_ssize_t DNBBreakpointGetHitCount (nub_process_t pid, nub_break_t breakID) DNB_EXPORT;
+nub_ssize_t DNBBreakpointGetIgnoreCount (nub_process_t pid, nub_break_t breakID) DNB_EXPORT;
+nub_bool_t DNBBreakpointSetIgnoreCount (nub_process_t pid, nub_break_t breakID, nub_size_t ignore_count) DNB_EXPORT;
+nub_bool_t DNBBreakpointSetCallback (nub_process_t pid, nub_break_t breakID, DNBCallbackBreakpointHit callback, void *baton) DNB_EXPORT;
+void DNBBreakpointPrint (nub_process_t pid, nub_break_t breakID) DNB_EXPORT;
+
+//----------------------------------------------------------------------
+// Watchpoint functions
+//----------------------------------------------------------------------
+nub_watch_t DNBWatchpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, uint32_t watch_flags, nub_bool_t hardware) DNB_EXPORT;
+nub_bool_t DNBWatchpointClear (nub_process_t pid, nub_watch_t watchID) DNB_EXPORT;
+nub_ssize_t DNBWatchpointGetHitCount (nub_process_t pid, nub_watch_t watchID) DNB_EXPORT;
+nub_ssize_t DNBWatchpointGetIgnoreCount (nub_process_t pid, nub_watch_t watchID) DNB_EXPORT;
+nub_bool_t DNBWatchpointSetIgnoreCount (nub_process_t pid, nub_watch_t watchID, nub_size_t ignore_count) DNB_EXPORT;
+nub_bool_t DNBWatchpointSetCallback (nub_process_t pid, nub_watch_t watchID, DNBCallbackBreakpointHit callback, void *baton) DNB_EXPORT;
+void DNBWatchpointPrint (nub_process_t pid, nub_watch_t watchID) DNB_EXPORT;
+
+const DNBRegisterSetInfo *
+ DNBGetRegisterSetInfo (nub_size_t *num_reg_sets) DNB_EXPORT;
+nub_bool_t DNBGetRegisterInfoByName (const char *reg_name, DNBRegisterInfo* info) DNB_EXPORT;
+
+//----------------------------------------------------------------------
+// Printf style formatting for printing values in the inferior memory
+// space and registers.
+//----------------------------------------------------------------------
+nub_size_t DNBPrintf (nub_process_t pid, nub_thread_t tid, nub_addr_t addr, FILE *file, const char *format) DNB_EXPORT;
+
+//----------------------------------------------------------------------
+// Other static nub information calls.
+//----------------------------------------------------------------------
+const char * DNBStateAsString (nub_state_t state) DNB_EXPORT;
+nub_bool_t DNBResolveExecutablePath (const char *path, char *resolved_path, size_t resolved_path_size) DNB_EXPORT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lldb/tools/debugserver/source/DNBArch.h b/lldb/tools/debugserver/source/DNBArch.h
new file mode 100644
index 00000000000..3eb2362aa0f
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBArch.h
@@ -0,0 +1,61 @@
+//===-- DNBArch.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/24/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DebugNubArch_h__
+#define __DebugNubArch_h__
+
+#include "DNBDefs.h"
+#include "MacOSX/MachException.h"
+
+#include <mach/mach.h>
+#include <stdio.h>
+
+struct DNBRegisterValue;
+struct DNBRegisterSetInfo;
+
+class DNBArchProtocol
+{
+public:
+ static const DNBRegisterSetInfo *
+ GetRegisterSetInfo (nub_size_t *num_reg_sets);
+
+ virtual bool GetRegisterValue (int set, int reg, DNBRegisterValue *value) = 0;
+ virtual bool SetRegisterValue (int set, int reg, const DNBRegisterValue *value) = 0;
+ virtual nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len) = 0;
+ virtual nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len) = 0;
+
+ virtual kern_return_t GetRegisterState (int set, bool force) = 0;
+ virtual kern_return_t SetRegisterState (int set) = 0;
+ virtual bool RegisterSetStateIsValid (int set) const = 0;
+
+ virtual uint64_t GetPC (uint64_t failValue) = 0; // Get program counter
+ virtual uint64_t GetSP (uint64_t failValue) = 0; // Get stack pointer
+ virtual void ThreadWillResume () = 0;
+ virtual bool ThreadDidStop () = 0;
+ virtual bool NotifyException (MachException::Data& exc) { return false; }
+ virtual uint32_t NumSupportedHardwareBreakpoints() { return 0; }
+ virtual uint32_t NumSupportedHardwareWatchpoints() { return 0; }
+ virtual uint32_t EnableHardwareBreakpoint (nub_addr_t addr, nub_size_t size) { return INVALID_NUB_HW_INDEX; }
+ virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write) { return INVALID_NUB_HW_INDEX; }
+ virtual bool DisableHardwareBreakpoint (uint32_t hw_index) { return false; }
+ virtual bool DisableHardwareWatchpoint (uint32_t hw_index) { return false; }
+ virtual bool StepNotComplete () { return false; }
+};
+
+
+#include "MacOSX/arm/DNBArchImpl.h"
+#include "MacOSX/i386/DNBArchImplI386.h"
+#include "MacOSX/x86_64/DNBArchImplX86_64.h"
+#include "MacOSX/ppc/DNBArchImpl.h"
+
+#endif
diff --git a/lldb/tools/debugserver/source/DNBBreakpoint.cpp b/lldb/tools/debugserver/source/DNBBreakpoint.cpp
new file mode 100644
index 00000000000..837f53260cf
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBBreakpoint.cpp
@@ -0,0 +1,303 @@
+//===-- DNBBreakpoint.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/29/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DNBBreakpoint.h"
+#include <algorithm>
+#include "DNBLog.h"
+
+
+#pragma mark -- DNBBreakpoint
+DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size, nub_thread_t tid, bool hardware) :
+ m_breakID(GetNextID()),
+ m_tid(tid),
+ m_byte_size(byte_size),
+ m_opcode(),
+ m_addr(addr),
+ m_enabled(0),
+ m_hw_preferred(hardware),
+ m_is_watchpoint(0),
+ m_watch_read(0),
+ m_watch_write(0),
+ m_hw_index(INVALID_NUB_HW_INDEX),
+ m_hit_count(0),
+ m_ignore_count(0),
+ m_callback(NULL),
+ m_callback_baton(NULL)
+{
+}
+
+DNBBreakpoint::~DNBBreakpoint()
+{
+}
+
+nub_break_t
+DNBBreakpoint::GetNextID()
+{
+ static uint32_t g_nextBreakID = 0;
+ return ++g_nextBreakID;
+}
+
+void
+DNBBreakpoint::SetCallback(DNBCallbackBreakpointHit callback, void *callback_baton)
+{
+ m_callback = callback;
+ m_callback_baton = callback_baton;
+}
+
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue.
+
+bool
+DNBBreakpoint::BreakpointHit(nub_process_t pid, nub_thread_t tid)
+{
+ m_hit_count++;
+
+ if (m_hit_count > m_ignore_count)
+ {
+ if (m_callback)
+ return m_callback(pid, tid, GetID(), m_callback_baton);
+ return true;
+ }
+ return false;
+}
+
+void
+DNBBreakpoint::Dump() const
+{
+ if (IsBreakpoint())
+ {
+ DNBLog("DNBBreakpoint %u: tid = %4.4x addr = %8.8p state = %s type = %s breakpoint hw_index = %i hit_count = %-4u ignore_count = %-4u callback = %8.8p baton = %8.8p",
+ m_breakID,
+ m_tid,
+ m_addr,
+ m_enabled ? "enabled " : "disabled",
+ IsHardware() ? "hardware" : "software",
+ GetHardwareIndex(),
+ GetHitCount(),
+ GetIgnoreCount(),
+ m_callback,
+ m_callback_baton);
+ }
+ else
+ {
+ DNBLog("DNBBreakpoint %u: tid = %4.4x addr = %8.8p size = %u state = %s type = %s watchpoint (%s%s) hw_index = %i hit_count = %-4u ignore_count = %-4u callback = %8.8p baton = %8.8p",
+ m_breakID,
+ m_tid,
+ m_addr,
+ m_byte_size,
+ m_enabled ? "enabled " : "disabled",
+ IsHardware() ? "hardware" : "software",
+ m_watch_read ? "r" : "",
+ m_watch_write ? "w" : "",
+ GetHardwareIndex(),
+ GetHitCount(),
+ GetIgnoreCount(),
+ m_callback,
+ m_callback_baton);
+ }
+}
+
+#pragma mark -- DNBBreakpointList
+
+DNBBreakpointList::DNBBreakpointList()
+{
+}
+
+DNBBreakpointList::~DNBBreakpointList()
+{
+}
+
+
+nub_break_t
+DNBBreakpointList::Add(const DNBBreakpoint& bp)
+{
+ m_breakpoints.push_back(bp);
+ return m_breakpoints.back().GetID();
+}
+
+bool
+DNBBreakpointList::ShouldStop(nub_process_t pid, nub_thread_t tid, nub_break_t breakID)
+{
+ DNBBreakpoint *bp = FindByID (breakID);
+ if (bp)
+ {
+ // Let the breakpoint 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->BreakpointHit(pid, tid);
+ }
+ // We should stop here since this breakpoint isn't valid anymore or it
+ // doesn't exist.
+ return true;
+}
+
+nub_break_t
+DNBBreakpointList::FindIDByAddress (nub_addr_t addr)
+{
+ DNBBreakpoint *bp = FindByAddress (addr);
+ if (bp)
+ {
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBBreakpointList::%s ( addr = 0x%8.8llx ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID());
+ return bp->GetID();
+ }
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBBreakpointList::%s ( addr = 0x%8.8llx ) => NONE", __FUNCTION__, (uint64_t)addr);
+ return INVALID_NUB_BREAK_ID;
+}
+
+bool
+DNBBreakpointList::Remove (nub_break_t breakID)
+{
+ iterator pos = GetBreakIDIterator(breakID); // Predicate
+ if (pos != m_breakpoints.end())
+ {
+ m_breakpoints.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+
+class BreakpointIDMatches
+{
+public:
+ BreakpointIDMatches (nub_break_t breakID) : m_breakID(breakID) {}
+ bool operator() (const DNBBreakpoint& bp) const
+ {
+ return m_breakID == bp.GetID();
+ }
+ private:
+ const nub_break_t m_breakID;
+};
+
+class BreakpointAddressMatches
+{
+public:
+ BreakpointAddressMatches (nub_addr_t addr) : m_addr(addr) {}
+ bool operator() (const DNBBreakpoint& bp) const
+ {
+ return m_addr == bp.Address();
+ }
+ private:
+ const nub_addr_t m_addr;
+};
+
+DNBBreakpointList::iterator
+DNBBreakpointList::GetBreakIDIterator (nub_break_t breakID)
+{
+ return std::find_if(m_breakpoints.begin(), m_breakpoints.end(), // Search full range
+ BreakpointIDMatches(breakID)); // Predicate
+}
+
+DNBBreakpointList::const_iterator
+DNBBreakpointList::GetBreakIDConstIterator (nub_break_t breakID) const
+{
+ return std::find_if(m_breakpoints.begin(), m_breakpoints.end(), // Search full range
+ BreakpointIDMatches(breakID)); // Predicate
+}
+
+DNBBreakpoint *
+DNBBreakpointList::FindByID (nub_break_t breakID)
+{
+ iterator pos = GetBreakIDIterator(breakID);
+ if (pos != m_breakpoints.end())
+ return &(*pos);
+
+ return NULL;
+}
+
+const DNBBreakpoint *
+DNBBreakpointList::FindByID (nub_break_t breakID) const
+{
+ const_iterator pos = GetBreakIDConstIterator(breakID);
+ if (pos != m_breakpoints.end())
+ return &(*pos);
+
+ return NULL;
+}
+
+DNBBreakpoint *
+DNBBreakpointList::FindByAddress (nub_addr_t addr)
+{
+ iterator end = m_breakpoints.end();
+ iterator pos = std::find_if(m_breakpoints.begin(), end, // Search full range
+ BreakpointAddressMatches(addr)); // Predicate
+ if (pos != end)
+ return &(*pos);
+
+ return NULL;
+}
+
+const DNBBreakpoint *
+DNBBreakpointList::FindByAddress (nub_addr_t addr) const
+{
+ const_iterator end = m_breakpoints.end();
+ const_iterator pos = std::find_if(m_breakpoints.begin(), end, // Search full range
+ BreakpointAddressMatches(addr)); // Predicate
+ if (pos != end)
+ return &(*pos);
+
+ return NULL;
+}
+
+bool
+DNBBreakpointList::SetCallback(nub_break_t breakID, DNBCallbackBreakpointHit callback, void *callback_baton)
+{
+ DNBBreakpoint *bp = FindByID (breakID);
+ if (bp)
+ {
+ bp->SetCallback(callback, callback_baton);
+ return true;
+ }
+ return false;
+}
+
+
+void
+DNBBreakpointList::Dump() const
+{
+ const_iterator pos;
+ const_iterator end = m_breakpoints.end();
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ (*pos).Dump();
+}
+
+
+DNBBreakpoint *
+DNBBreakpointList::GetByIndex (uint32_t i)
+{
+ iterator end = m_breakpoints.end();
+ iterator pos;
+ uint32_t curr_i = 0;
+ for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
+ {
+ if (curr_i == i)
+ return &(*pos);
+ }
+ return NULL;
+}
+
+const DNBBreakpoint *
+DNBBreakpointList::GetByIndex (uint32_t i) const
+{
+ const_iterator end = m_breakpoints.end();
+ const_iterator pos;
+ uint32_t curr_i = 0;
+ for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
+ {
+ if (curr_i == i)
+ return &(*pos);
+ }
+ return NULL;
+}
+
diff --git a/lldb/tools/debugserver/source/DNBBreakpoint.h b/lldb/tools/debugserver/source/DNBBreakpoint.h
new file mode 100644
index 00000000000..28c967a0525
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBBreakpoint.h
@@ -0,0 +1,159 @@
+//===-- DNBBreakpoint.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/29/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DNBBreakpoint_h__
+#define __DNBBreakpoint_h__
+
+#include <list>
+
+#include "DNBDefs.h"
+
+class DNBBreakpoint
+{
+public:
+ DNBBreakpoint(nub_addr_t m_addr, nub_size_t byte_size, nub_thread_t tid, bool hardware);
+ ~DNBBreakpoint();
+
+ nub_break_t GetID() const { return m_breakID; }
+ nub_size_t ByteSize() const { return m_byte_size; }
+ uint8_t * SavedOpcodeBytes() { return &m_opcode[0]; }
+ const uint8_t *
+ SavedOpcodeBytes() const { return &m_opcode[0]; }
+ nub_addr_t Address() const { return m_addr; }
+ nub_thread_t ThreadID() const { return m_tid; }
+ bool IsEnabled() const { return m_enabled; }
+ bool IntersectsRange(nub_addr_t addr, nub_size_t size, nub_addr_t *intersect_addr, nub_size_t *intersect_size, nub_size_t *opcode_offset) const
+ {
+ // We only use software traps for software breakpoints
+ if (IsBreakpoint() && IsEnabled() && !IsHardware())
+ {
+ if (m_byte_size > 0)
+ {
+ const nub_addr_t bp_end_addr = m_addr + m_byte_size;
+ const nub_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<nub_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<nub_addr_t>(bp_end_addr, end_addr) - m_addr;
+ if (opcode_offset)
+ *opcode_offset = 0;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+ void SetEnabled(uint32_t enabled)
+ {
+ if (!enabled)
+ SetHardwareIndex(INVALID_NUB_HW_INDEX);
+ m_enabled = enabled;
+ }
+ void SetIsWatchpoint (uint32_t type)
+ {
+ m_is_watchpoint = 1;
+ m_watch_read = (type & WATCH_TYPE_READ) != 0;
+ m_watch_write = (type & WATCH_TYPE_WRITE) != 0;
+ }
+ bool IsBreakpoint() const { return m_is_watchpoint == 0; }
+ bool IsWatchpoint() const { return m_is_watchpoint == 1; }
+ bool WatchpointRead() const { return m_watch_read != 0; }
+ bool WatchpointWrite() const { return m_watch_write != 0; }
+ bool HardwarePreferred() const { return m_hw_preferred; }
+ bool IsHardware() const { return m_hw_index != INVALID_NUB_HW_INDEX; }
+ uint32_t GetHardwareIndex() const { return m_hw_index; }
+ void SetHardwareIndex(uint32_t hw_index) { m_hw_index = hw_index; }
+// StateType GetState() const { return m_state; }
+// void SetState(StateType newState) { m_state = newState; }
+ int32_t GetHitCount() const { return m_hit_count; }
+ int32_t GetIgnoreCount() const { return m_ignore_count; }
+ void SetIgnoreCount(int32_t n) { m_ignore_count = n; }
+ bool BreakpointHit(nub_process_t pid, nub_thread_t tid);
+ void SetCallback(DNBCallbackBreakpointHit callback, void *callback_baton);
+ void Dump() const;
+
+private:
+ nub_break_t m_breakID; // The unique identifier for this breakpoint
+ nub_thread_t m_tid; // Thread ID for the breakpoint (can be INVALID_NUB_THREAD for all threads)
+ nub_size_t m_byte_size; // Length in bytes of the breakpoint if set in memory
+ uint8_t m_opcode[8]; // Saved opcode bytes
+ nub_addr_t m_addr; // Address of this breakpoint
+ uint32_t m_enabled:1, // Flags for this breakpoint
+ m_hw_preferred:1, // 1 if this point has been requested to be set using hardware (which may fail due to lack of resources)
+ m_is_watchpoint:1, // 1 if this is a watchpoint
+ 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
+ uint32_t m_hw_index; // The hardware resource index for this breakpoint/watchpoint
+ int32_t m_hit_count; // Number of times this breakpoint has been hit
+ int32_t m_ignore_count; // Number of times to ignore this breakpoint
+ DNBCallbackBreakpointHit
+ m_callback; // Callback to call when this breakpoint gets hit
+ void * m_callback_baton; // Callback user data to pass to callback
+
+ static nub_break_t GetNextID();
+
+};
+
+
+class DNBBreakpointList
+{
+public:
+ DNBBreakpointList();
+ ~DNBBreakpointList();
+
+ nub_break_t Add (const DNBBreakpoint& bp);
+ nub_break_t FindIDByAddress (nub_addr_t addr);
+ bool ShouldStop (nub_process_t pid, nub_thread_t tid, nub_break_t breakID);
+ bool Remove (nub_break_t breakID);
+ bool SetCallback (nub_break_t breakID, DNBCallbackBreakpointHit callback, void *callback_baton);
+ DNBBreakpoint * FindByAddress (nub_addr_t addr);
+ const DNBBreakpoint * FindByAddress (nub_addr_t addr) const;
+ DNBBreakpoint * FindByID (nub_break_t breakID);
+ const DNBBreakpoint * FindByID (nub_break_t breakID) const;
+ void Dump () const;
+
+ size_t Size() const { return m_breakpoints.size(); }
+ DNBBreakpoint * GetByIndex (uint32_t i);
+ const DNBBreakpoint * GetByIndex (uint32_t i) const;
+
+protected:
+ typedef std::list<DNBBreakpoint> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ iterator GetBreakIDIterator(nub_break_t breakID);
+ const_iterator GetBreakIDConstIterator(nub_break_t breakID) const;
+ collection m_breakpoints;
+};
+
+#endif
+
diff --git a/lldb/tools/debugserver/source/DNBDataRef.cpp b/lldb/tools/debugserver/source/DNBDataRef.cpp
new file mode 100644
index 00000000000..271c205e024
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBDataRef.cpp
@@ -0,0 +1,485 @@
+//===-- DNBDataRef.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 1/11/06.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DNBDataRef.h"
+#include "DNBLog.h"
+#include <assert.h>
+#include <ctype.h>
+#include <libkern/OSByteOrder.h>
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+
+DNBDataRef::DNBDataRef() :
+ m_start(NULL),
+ m_end(NULL),
+ m_swap(false),
+ m_ptrSize(0),
+ m_addrPCRelative(INVALID_NUB_ADDRESS),
+ m_addrTEXT(INVALID_NUB_ADDRESS),
+ m_addrDATA(INVALID_NUB_ADDRESS)
+{
+}
+
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+
+DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap) :
+ m_start(start),
+ m_end(start+size),
+ m_swap(swap),
+ m_ptrSize(0),
+ m_addrPCRelative(INVALID_NUB_ADDRESS),
+ m_addrTEXT(INVALID_NUB_ADDRESS),
+ m_addrDATA(INVALID_NUB_ADDRESS)
+{
+}
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+
+DNBDataRef::~DNBDataRef()
+{
+}
+
+
+//----------------------------------------------------------------------
+// Get8
+//----------------------------------------------------------------------
+uint8_t
+DNBDataRef::Get8(offset_t *offset_ptr) const
+{
+ uint8_t val = 0;
+ if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) )
+ {
+ val = *(m_start + *offset_ptr);
+ *offset_ptr += sizeof(val);
+ }
+ return val;
+}
+
+
+//----------------------------------------------------------------------
+// Get16
+//----------------------------------------------------------------------
+uint16_t
+DNBDataRef::Get16(offset_t *offset_ptr) const
+{
+ uint16_t val = 0;
+ if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) )
+ {
+ const uint8_t *p = m_start + *offset_ptr;
+ val = *(uint16_t*)p;
+
+ if (m_swap)
+ val = OSSwapInt16(val);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ return val;
+}
+
+
+//----------------------------------------------------------------------
+// Get32
+//----------------------------------------------------------------------
+uint32_t
+DNBDataRef::Get32(offset_t *offset_ptr) const
+{
+ uint32_t val = 0;
+ if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) )
+ {
+ const uint8_t *p = m_start + *offset_ptr;
+ val = *(uint32_t*)p;
+ if (m_swap)
+ val = OSSwapInt32(val);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ return val;
+}
+
+
+//----------------------------------------------------------------------
+// Get64
+//----------------------------------------------------------------------
+uint64_t
+DNBDataRef::Get64(offset_t *offset_ptr) const
+{
+ uint64_t val = 0;
+ if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) )
+ {
+ const uint8_t *p = m_start + *offset_ptr;
+ val = *(uint64_t*)p;
+ if (m_swap)
+ val = OSSwapInt64(val);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
+ }
+ return val;
+}
+
+
+//----------------------------------------------------------------------
+// GetMax32
+//
+// Used for calls when the size can vary. Fill in extra cases if they
+// are ever needed.
+//----------------------------------------------------------------------
+uint32_t
+DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const
+{
+ switch (byte_size)
+ {
+ case 1: return Get8 (offset_ptr); break;
+ case 2: return Get16(offset_ptr); break;
+ case 4: return Get32(offset_ptr); break;
+ default:
+ assert(!"GetMax32 unhandled case!");
+ break;
+ }
+ return 0;
+}
+
+
+//----------------------------------------------------------------------
+// GetMax64
+//
+// Used for calls when the size can vary. Fill in extra cases if they
+// are ever needed.
+//----------------------------------------------------------------------
+uint64_t
+DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const
+{
+ switch (size)
+ {
+ case 1: return Get8 (offset_ptr); break;
+ case 2: return Get16(offset_ptr); break;
+ case 4: return Get32(offset_ptr); break;
+ case 8: return Get64(offset_ptr); break;
+ default:
+ assert(!"GetMax64 unhandled case!");
+ break;
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// GetPointer
+//
+// Extract a pointer value from the buffer. The pointer size must be
+// set prior to using this using one of the SetPointerSize functions.
+//----------------------------------------------------------------------
+uint64_t
+DNBDataRef::GetPointer(offset_t *offset_ptr) const
+{
+ // Must set pointer size prior to using this call
+ assert(m_ptrSize != 0);
+ return GetMax64(offset_ptr, m_ptrSize);
+}
+
+//----------------------------------------------------------------------
+// GetDwarfEHPtr
+//
+// Used for calls when the value type is specified by a DWARF EH Frame
+// pointer encoding.
+//----------------------------------------------------------------------
+/*
+uint64_t
+DNBDataRef::GetDwarfEHPtr(offset_t *offset_ptr, uint32_t encoding) const
+{
+ if (encoding == DW_EH_PE_omit)
+ return ULONG_LONG_MAX; // Value isn't in the buffer...
+
+ uint64_t baseAddress = 0;
+ uint64_t addressValue = 0;
+
+ BOOL signExtendValue = NO;
+ // Decode the base part or adjust our offset
+ switch (encoding & 0x70)
+ {
+ case DW_EH_PE_pcrel:
+ // SetEHPtrBaseAddresses should be called prior to extracting these
+ // so the base addresses are cached.
+ assert(m_addrPCRelative != INVALID_NUB_ADDRESS);
+ signExtendValue = YES;
+ baseAddress = *offset_ptr + m_addrPCRelative;
+ break;
+
+ case DW_EH_PE_textrel:
+ // SetEHPtrBaseAddresses should be called prior to extracting these
+ // so the base addresses are cached.
+ assert(m_addrTEXT != INVALID_NUB_ADDRESS);
+ signExtendValue = YES;
+ baseAddress = m_addrTEXT;
+ break;
+
+ case DW_EH_PE_datarel:
+ // SetEHPtrBaseAddresses should be called prior to extracting these
+ // so the base addresses are cached.
+ assert(m_addrDATA != INVALID_NUB_ADDRESS);
+ signExtendValue = YES;
+ baseAddress = m_addrDATA;
+ break;
+
+ case DW_EH_PE_funcrel:
+ signExtendValue = YES;
+ break;
+
+ case DW_EH_PE_aligned:
+ // SetPointerSize should be called prior to extracting these so the
+ // pointer size is cached
+ assert(m_ptrSize != 0);
+ if (m_ptrSize)
+ {
+ // Align to a address size boundary first
+ uint32_t alignOffset = *offset_ptr % m_ptrSize;
+ if (alignOffset)
+ offset_ptr += m_ptrSize - alignOffset;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Decode the value part
+ switch (encoding & DW_EH_PE_MASK_ENCODING)
+ {
+ case DW_EH_PE_absptr : addressValue = GetPointer(offset_ptr); break;
+ case DW_EH_PE_uleb128 : addressValue = Get_ULEB128(offset_ptr); break;
+ case DW_EH_PE_udata2 : addressValue = Get16(offset_ptr); break;
+ case DW_EH_PE_udata4 : addressValue = Get32(offset_ptr); break;
+ case DW_EH_PE_udata8 : addressValue = Get64(offset_ptr); break;
+ case DW_EH_PE_sleb128 : addressValue = Get_SLEB128(offset_ptr); break;
+ case DW_EH_PE_sdata2 : addressValue = (int16_t)Get16(offset_ptr); break;
+ case DW_EH_PE_sdata4 : addressValue = (int32_t)Get32(offset_ptr); break;
+ case DW_EH_PE_sdata8 : addressValue = (int64_t)Get64(offset_ptr); break;
+ default:
+ // Unhandled encoding type
+ assert(encoding);
+ break;
+ }
+
+ // Since we promote everything to 64 bit, we may need to sign extend
+ if (signExtendValue && m_ptrSize < sizeof(baseAddress))
+ {
+ uint64_t sign_bit = 1ull << ((m_ptrSize * 8ull) - 1ull);
+ if (sign_bit & addressValue)
+ {
+ uint64_t mask = ~sign_bit + 1;
+ addressValue |= mask;
+ }
+ }
+ return baseAddress + addressValue;
+}
+*/
+
+
+//----------------------------------------------------------------------
+// GetCStr
+//----------------------------------------------------------------------
+const char *
+DNBDataRef::GetCStr(offset_t *offset_ptr, uint32_t fixed_length) const
+{
+ const char *s = NULL;
+ if ( m_start < m_end )
+ {
+ s = (char*)m_start + *offset_ptr;
+
+ // Advance the offset
+ if (fixed_length)
+ *offset_ptr += fixed_length;
+ else
+ *offset_ptr += strlen(s) + 1;
+ }
+ return s;
+}
+
+
+//----------------------------------------------------------------------
+// GetData
+//----------------------------------------------------------------------
+const uint8_t *
+DNBDataRef::GetData(offset_t *offset_ptr, uint32_t length) const
+{
+ const uint8_t *data = NULL;
+ if ( length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length) )
+ {
+ data = m_start + *offset_ptr;
+ *offset_ptr += length;
+ }
+ return data;
+}
+
+
+//----------------------------------------------------------------------
+// Get_ULEB128
+//----------------------------------------------------------------------
+uint64_t
+DNBDataRef::Get_ULEB128 (offset_t *offset_ptr) const
+{
+ uint64_t result = 0;
+ if ( m_start < m_end )
+ {
+ int shift = 0;
+ const uint8_t *src = m_start + *offset_ptr;
+ uint8_t byte;
+ int bytecount = 0;
+
+ while (src < m_end)
+ {
+ bytecount++;
+ byte = *src++;
+ result |= (byte & 0x7f) << shift;
+ shift += 7;
+ if ((byte & 0x80) == 0)
+ break;
+ }
+
+ *offset_ptr += bytecount;
+ }
+ return result;
+}
+
+
+//----------------------------------------------------------------------
+// Get_SLEB128
+//----------------------------------------------------------------------
+int64_t
+DNBDataRef::Get_SLEB128 (offset_t *offset_ptr) const
+{
+ int64_t result = 0;
+
+ if ( m_start < m_end )
+ {
+ int shift = 0;
+ int size = sizeof (uint32_t) * 8;
+ const uint8_t *src = m_start + *offset_ptr;
+
+ uint8_t byte;
+ int bytecount = 0;
+
+ while (src < m_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 |= - (1ll << shift);
+
+ *offset_ptr += bytecount;
+ }
+ return result;
+}
+
+
+//----------------------------------------------------------------------
+// Skip_LEB128
+//
+// Skips past ULEB128 and SLEB128 numbers (just updates the offset)
+//----------------------------------------------------------------------
+void
+DNBDataRef::Skip_LEB128 (offset_t *offset_ptr) const
+{
+ if ( m_start < m_end )
+ {
+ const uint8_t *start = m_start + *offset_ptr;
+ const uint8_t *src = start;
+
+ while ((src < m_end) && (*src++ & 0x80))
+ /* Do nothing */;
+
+ *offset_ptr += src - start;
+ }
+}
+
+uint32_t
+DNBDataRef::Dump
+(
+ uint32_t startOffset,
+ uint32_t endOffset,
+ uint64_t offsetBase,
+ DNBDataRef::Type type,
+ uint32_t numPerLine,
+ const char *format
+)
+{
+ uint32_t offset;
+ uint32_t count;
+ char str[1024];
+ str[0] = '\0';
+ int str_offset = 0;
+
+ for (offset = startOffset, count = 0; ValidOffset(offset) && offset < endOffset; ++count)
+ {
+ if ((count % numPerLine) == 0)
+ {
+ // Print out any previous string
+ if (str[0] != '\0')
+ DNBLog("%s", str);
+ // Reset string offset and fill the current line string with address:
+ str_offset = 0;
+ str_offset += snprintf(str, sizeof(str), "0x%8.8llx:", (uint64_t)(offsetBase + (offset - startOffset)));
+ }
+
+ // Make sure we don't pass the bounds of our current string buffer on each iteration through this loop
+ if (str_offset >= sizeof(str))
+ {
+ // The last snprintf consumed our string buffer, we will need to dump this out
+ // and reset the string with no address
+ DNBLog("%s", str);
+ str_offset = 0;
+ str[0] = '\0';
+ }
+
+ // We already checked that there is at least some room in the string str above, so it is safe to make
+ // the snprintf call each time through this loop
+ switch (type)
+ {
+ default:
+ case TypeUInt8: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %2.2x", Get8(&offset)); break;
+ case TypeChar:
+ {
+ char ch = Get8(&offset);
+ str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %c", isprint(ch) ? ch : ' ');
+ }
+ break;
+ case TypeUInt16: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %4.4x", Get16(&offset)); break;
+ case TypeUInt32: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %8.8x", Get32(&offset)); break;
+ case TypeUInt64: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %16.16llx", Get64(&offset)); break;
+ case TypePointer: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " 0x%llx", GetPointer(&offset)); break;
+ case TypeULEB128: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " 0x%llx", Get_ULEB128(&offset)); break;
+ case TypeSLEB128: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %lld", Get_SLEB128(&offset)); break;
+ }
+ }
+
+ if (str[0] != '\0')
+ DNBLog("%s", str);
+
+ return offset; // Return the offset at which we ended up
+}
diff --git a/lldb/tools/debugserver/source/DNBDataRef.h b/lldb/tools/debugserver/source/DNBDataRef.h
new file mode 100644
index 00000000000..fbecb7d4a76
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBDataRef.h
@@ -0,0 +1,111 @@
+//===-- DNBDataRef.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 1/11/06.
+//
+//===----------------------------------------------------------------------===//
+//
+// DNBDataRef is a class that can extract data in normal or byte
+// swapped order from a data buffer that someone else owns. The data
+// buffer needs to remain intact as long as the DNBDataRef object
+// needs the data. Strings returned are pointers into the data buffer
+// and will need to be copied if they are needed after the data buffer
+// is no longer around.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DNBDataRef_h__
+#define __DNBDataRef_h__
+
+#include "DNBDefs.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+class DNBDataRef
+{
+public:
+ // For use with Dump
+ typedef enum
+ {
+ TypeUInt8 = 0,
+ TypeChar,
+ TypeUInt16,
+ TypeUInt32,
+ TypeUInt64,
+ TypePointer,
+ TypeULEB128,
+ TypeSLEB128
+ } Type;
+ typedef uint32_t offset_t;
+ typedef nub_addr_t addr_t;
+
+ DNBDataRef();
+ DNBDataRef(const uint8_t *start, size_t size, bool swap);
+ ~DNBDataRef();
+ void Clear()
+ {
+ DNBDataRef::SetData(NULL, 0);
+ m_swap = false;
+ }
+
+ bool ValidOffset(offset_t offset) const { return (m_start < m_end) && ((uint32_t)(m_end - m_start) > offset); }
+ bool ValidOffsetForDataOfSize(offset_t offset, uint32_t num_bytes) const { return (m_start < m_end) && ((uint32_t)(m_end - m_start) > (offset + ((num_bytes > 0) ? (num_bytes - 1) : 0))); }
+ size_t GetSize() const { return m_end - m_start; }
+ const uint8_t * GetDataStart() const { return m_start; }
+ const uint8_t * GetDataEnd() const { return m_end; }
+ bool GetSwap() const { return m_swap; }
+ void SetSwap(bool swap) { m_swap = swap; }
+ void SetData(const uint8_t *start, size_t size)
+ {
+ m_start = start;
+ if (m_start != NULL)
+ m_end = start + size;
+ else
+ m_end = NULL;
+ }
+ uint8_t GetPointerSize() const { return m_ptrSize; }
+ void SetPointerSize(uint8_t size) { m_ptrSize = size; }
+ void SetEHPtrBaseAddrPCRelative(addr_t addr = INVALID_NUB_ADDRESS) { m_addrPCRelative = addr; }
+ void SetEHPtrBaseAddrTEXT(addr_t addr = INVALID_NUB_ADDRESS) { m_addrTEXT = addr; }
+ void SetEHPtrBaseAddrDATA(addr_t addr = INVALID_NUB_ADDRESS) { m_addrDATA = addr; }
+ uint8_t Get8(offset_t *offset_ptr) const;
+ uint16_t Get16(offset_t *offset_ptr) const;
+ uint32_t Get32(offset_t *offset_ptr) const;
+ uint64_t Get64(offset_t *offset_ptr) const;
+ uint32_t GetMax32(offset_t *offset_ptr, uint32_t byte_size) const;
+ uint64_t GetMax64(offset_t *offset_ptr, uint32_t byte_size) const;
+ uint64_t GetPointer(offset_t *offset_ptr) const;
+// uint64_t GetDwarfEHPtr(offset_t *offset_ptr, uint32_t eh_ptr_enc) const;
+ const char * GetCStr(offset_t *offset_ptr, uint32_t fixed_length = 0) const;
+ const char * PeekCStr(offset_t offset) const
+ {
+ if (ValidOffset(offset))
+ return (const char*)m_start + offset;
+ return NULL;
+ }
+
+ const uint8_t * GetData( offset_t *offset_ptr, uint32_t length) const;
+ uint64_t Get_ULEB128 (offset_t *offset_ptr) const;
+ int64_t Get_SLEB128 (offset_t *offset_ptr) const;
+ void Skip_LEB128 (offset_t *offset_ptr) const;
+
+ uint32_t Dump(offset_t startOffset, offset_t endOffset, uint64_t offsetBase, DNBDataRef::Type type, uint32_t numPerLine, const char *typeFormat = NULL);
+protected:
+ const uint8_t * m_start;
+ const uint8_t * m_end;
+ bool m_swap;
+ uint8_t m_ptrSize;
+ addr_t m_addrPCRelative;
+ addr_t m_addrTEXT;
+ addr_t m_addrDATA;
+};
+
+#endif // #ifndef __DNBDataRef_h__
diff --git a/lldb/tools/debugserver/source/DNBDefs.h b/lldb/tools/debugserver/source/DNBDefs.h
new file mode 100644
index 00000000000..23960ef4957
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBDefs.h
@@ -0,0 +1,331 @@
+//===-- DNBDefs.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/26/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DNBDefs_h__
+#define __DNBDefs_h__
+
+#include <stdint.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/syslimits.h>
+#include <unistd.h>
+
+//----------------------------------------------------------------------
+// Define nub_addr_t and the invalid address value from the architecture
+//----------------------------------------------------------------------
+#if defined (__x86_64__) || defined (__ppc64__)
+
+//----------------------------------------------------------------------
+// 64 bit address architectures
+//----------------------------------------------------------------------
+typedef uint64_t nub_addr_t;
+#define INVALID_NUB_ADDRESS ((nub_addr_t)~0ull)
+
+#elif defined (__i386__) || defined (__powerpc__) || defined (__ppc__) || defined (__arm__)
+
+//----------------------------------------------------------------------
+// 32 bit address architectures
+//----------------------------------------------------------------------
+
+typedef uint32_t nub_addr_t;
+#define INVALID_NUB_ADDRESS ((nub_addr_t)~0ul)
+
+#else
+
+//----------------------------------------------------------------------
+// Default to 64 bit address for unrecognized architectures.
+//----------------------------------------------------------------------
+
+#warning undefined architecture, defaulting to 8 byte addresses
+typedef uint64_t nub_addr_t;
+#define INVALID_NUB_ADDRESS ((nub_addr_t)~0ull)
+
+
+#endif
+
+typedef size_t nub_size_t;
+typedef ssize_t nub_ssize_t;
+typedef uint32_t nub_break_t;
+typedef uint32_t nub_watch_t;
+typedef uint32_t nub_index_t;
+typedef pid_t nub_process_t;
+typedef unsigned int nub_thread_t;
+typedef uint32_t nub_event_t;
+typedef uint32_t nub_bool_t;
+
+#define INVALID_NUB_BREAK_ID ((nub_break_t)0)
+#define INVALID_NUB_PROCESS ((nub_process_t)0)
+#define INVALID_NUB_THREAD ((nub_thread_t)0)
+#define INVALID_NUB_HW_INDEX UINT32_MAX
+#define INVALID_NUB_REGNUM UINT32_MAX
+#define NUB_GENERIC_ERROR UINT32_MAX
+
+#define NUB_BREAK_ID_IS_VALID(breakID) ((breakID) != (INVALID_NUB_BREAK_ID))
+
+// Watchpoint types
+#define WATCH_TYPE_READ (1u << 0)
+#define WATCH_TYPE_WRITE (1u << 1)
+
+typedef enum
+{
+ eStateInvalid = 0,
+ eStateUnloaded,
+ eStateAttaching,
+ eStateLaunching,
+ eStateStopped,
+ eStateRunning,
+ eStateStepping,
+ eStateCrashed,
+ eStateDetached,
+ eStateExited,
+ eStateSuspended
+} nub_state_t;
+
+typedef enum
+{
+ eLaunchFlavorDefault = 0,
+ eLaunchFlavorPosixSpawn,
+ eLaunchFlavorForkExec,
+#if defined (__arm__)
+ eLaunchFlavorSpringBoard,
+#endif
+} nub_launch_flavor_t;
+
+#define NUB_STATE_IS_RUNNING(s) ((s) == eStateAttaching ||\
+ (s) == eStateLaunching ||\
+ (s) == eStateRunning ||\
+ (s) == eStateStepping ||\
+ (s) == eStateDetached)
+
+#define NUB_STATE_IS_STOPPED(s) ((s) == eStateUnloaded ||\
+ (s) == eStateStopped ||\
+ (s) == eStateCrashed ||\
+ (s) == eStateExited)
+
+enum
+{
+ eEventProcessRunningStateChanged = 1 << 0, // The process has changed state to running
+ eEventProcessStoppedStateChanged = 1 << 1, // The process has changed state to stopped
+ eEventSharedLibsStateChange = 1 << 2, // Shared libraries loaded/unloaded state has changed
+ eEventStdioAvailable = 1 << 3, // Something is available on stdout/stderr
+ eEventProcessAsyncInterrupt = 1 << 4, // Gives the ability for any infinite wait calls to be interrupted
+ kAllEventsMask = eEventProcessRunningStateChanged |
+ eEventProcessStoppedStateChanged |
+ eEventSharedLibsStateChange |
+ eEventStdioAvailable |
+ eEventProcessAsyncInterrupt
+};
+
+#define LOG_VERBOSE (1u << 0)
+#define LOG_PROCESS (1u << 1)
+#define LOG_THREAD (1u << 2)
+#define LOG_EXCEPTIONS (1u << 3)
+#define LOG_SHLIB (1u << 4)
+#define LOG_MEMORY (1u << 5) // Log memory reads/writes calls
+#define LOG_MEMORY_DATA_SHORT (1u << 6) // Log short memory reads/writes bytes
+#define LOG_MEMORY_DATA_LONG (1u << 7) // Log all memory reads/writes bytes
+#define LOG_MEMORY_PROTECTIONS (1u << 8) // Log memory protection changes
+#define LOG_BREAKPOINTS (1u << 9)
+#define LOG_EVENTS (1u << 10)
+#define LOG_WATCHPOINTS (1u << 11)
+#define LOG_STEP (1u << 12)
+#define LOG_TASK (1u << 13)
+#define LOG_LO_USER (1u << 16)
+#define LOG_HI_USER (1u << 31)
+#define LOG_ALL 0xFFFFFFFFu
+#define LOG_DEFAULT ((LOG_PROCESS) |\
+ (LOG_TASK) |\
+ (LOG_THREAD) |\
+ (LOG_EXCEPTIONS) |\
+ (LOG_SHLIB) |\
+ (LOG_MEMORY) |\
+ (LOG_BREAKPOINTS) |\
+ (LOG_WATCHPOINTS) |\
+ (LOG_STEP))
+
+
+#define REGISTER_SET_ALL 0
+// Generic Register set to be defined by each architecture for access to common
+// register values.
+#define REGISTER_SET_GENERIC ((uint32_t)0xFFFFFFFFu)
+#define GENERIC_REGNUM_PC 0 // Program Counter
+#define GENERIC_REGNUM_SP 1 // Stack Pointer
+#define GENERIC_REGNUM_FP 2 // Frame Pointer
+#define GENERIC_REGNUM_RA 3 // Return Address
+#define GENERIC_REGNUM_FLAGS 4 // Processor flags register
+
+enum DNBRegisterType
+{
+ InvalidRegType = 0,
+ Uint, // unsigned integer
+ Sint, // signed integer
+ IEEE754, // float
+ Vector // vector registers
+};
+
+enum DNBRegisterFormat
+{
+ InvalidRegFormat = 0,
+ Binary,
+ Decimal,
+ Hex,
+ Float,
+ VectorOfSInt8,
+ VectorOfUInt8,
+ VectorOfSInt16,
+ VectorOfUInt16,
+ VectorOfSInt32,
+ VectorOfUInt32,
+ VectorOfFloat32,
+ VectorOfUInt128
+};
+
+struct DNBRegisterInfo
+{
+ uint32_t set; // Register set
+ uint32_t reg; // Register number
+ const char *name; // Name of this register
+ const char *alt; // Alternate name
+ uint16_t type; // Type of the register bits (DNBRegisterType)
+ uint16_t format; // Default format for display (DNBRegisterFormat),
+ uint32_t size; // Size in bytes of the register
+ uint32_t offset; // Offset from the beginning of the register context
+ uint32_t reg_gcc; // GCC register number (INVALID_NUB_REGNUM when none)
+ uint32_t reg_dwarf; // DWARF register number (INVALID_NUB_REGNUM when none)
+ uint32_t reg_generic; // Generic register number (INVALID_NUB_REGNUM when none)
+ uint32_t reg_gdb; // The GDB register number (INVALID_NUB_REGNUM when none)
+};
+
+struct DNBRegisterSetInfo
+{
+ const char *name; // Name of this register set
+ const struct DNBRegisterInfo *registers; // An array of register descriptions
+ nub_size_t num_registers; // The number of registers in REGISTERS array above
+};
+
+struct DNBThreadResumeAction
+{
+ nub_thread_t tid; // The thread ID that this action applies to, INVALID_NUB_THREAD for the default thread action
+ nub_state_t state; // Valid values are eStateStopped/eStateSuspended, eStateRunning, and eStateStepping.
+ int signal; // When resuming this thread, resume it with this signal
+ nub_addr_t addr; // If not INVALID_NUB_ADDRESS, then set the PC for the thread to ADDR before resuming/stepping
+};
+
+enum DNBThreadStopType
+{
+ eStopTypeInvalid = 0,
+ eStopTypeSignal,
+ eStopTypeException
+};
+
+enum DNBMemoryPermissions
+{
+ eMemoryPermissionsWritable = (1 << 0),
+ eMemoryPermissionsReadable = (1 << 1),
+ eMemoryPermissionsExecutable = (1 << 2)
+};
+
+#define DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH 256
+#define DNB_THREAD_STOP_INFO_MAX_EXC_DATA 8
+
+//----------------------------------------------------------------------
+// DNBThreadStopInfo
+//
+// Describes the reason a thread stopped.
+//----------------------------------------------------------------------
+struct DNBThreadStopInfo
+{
+ DNBThreadStopType reason;
+ char description[DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH];
+ union
+ {
+ // eStopTypeSignal
+ struct
+ {
+ uint32_t signo;
+ } signal;
+
+ // eStopTypeException
+ struct
+ {
+ uint32_t type;
+ nub_size_t data_count;
+ nub_addr_t data[DNB_THREAD_STOP_INFO_MAX_EXC_DATA];
+ } exception;
+ } details;
+};
+
+
+struct DNBRegisterValue
+{
+ struct DNBRegisterInfo info; // Register information for this register
+ union
+ {
+ int8_t sint8;
+ int16_t sint16;
+ int32_t sint32;
+ int64_t sint64;
+ uint8_t uint8;
+ uint16_t uint16;
+ uint32_t uint32;
+ uint64_t uint64;
+ float float32;
+ double float64;
+ int8_t v_sint8[16];
+ int16_t v_sint16[8];
+ int32_t v_sint32[4];
+ int64_t v_sint64[2];
+ uint8_t v_uint8[16];
+ uint16_t v_uint16[8];
+ uint32_t v_uint32[4];
+ uint64_t v_uint64[2];
+ float v_float32[4];
+ double v_float64[2];
+ void *pointer;
+ char *c_str;
+ } value;
+};
+
+enum DNBSharedLibraryState
+{
+ eShlibStateUnloaded = 0,
+ eShlibStateLoaded = 1
+};
+
+#ifndef DNB_MAX_SEGMENT_NAME_LENGTH
+#define DNB_MAX_SEGMENT_NAME_LENGTH 32
+#endif
+
+struct DNBSegment
+{
+ char name[DNB_MAX_SEGMENT_NAME_LENGTH];
+ nub_addr_t addr;
+ nub_addr_t size;
+};
+
+struct DNBExecutableImageInfo
+{
+ char name[PATH_MAX]; // Name of the executable image (usually a full path)
+ uint32_t state; // State of the executable image (see enum DNBSharedLibraryState)
+ nub_addr_t header_addr; // Executable header address
+ uuid_t uuid; // Unique indentifier for matching with symbols
+ uint32_t num_segments; // Number of contiguous memory segments to in SEGMENTS array
+ DNBSegment *segments; // Array of contiguous memory segments in executable
+};
+
+typedef nub_bool_t (*DNBCallbackBreakpointHit)(nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton);
+typedef nub_addr_t (*DNBCallbackNameToAddress)(nub_process_t pid, const char *name, const char *shlib_regex, void *baton);
+typedef nub_size_t (*DNBCallbackCopyExecutableImageInfos)(nub_process_t pid, struct DNBExecutableImageInfo **image_infos, nub_bool_t only_changed, void *baton);
+typedef void (*DNBCallbackLog)(void *baton, uint32_t flags, const char *format, va_list args);
+
+#endif // #ifndef __DNBDefs_h__
diff --git a/lldb/tools/debugserver/source/DNBError.cpp b/lldb/tools/debugserver/source/DNBError.cpp
new file mode 100644
index 00000000000..8f6294bfb51
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBError.cpp
@@ -0,0 +1,108 @@
+//===-- DNBError.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/26/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DNBError.h"
+#include "CFString.h"
+#include "DNBLog.h"
+#include "PThreadMutex.h"
+
+#if defined (__arm__)
+#include <SpringBoardServices/SpringBoardServer.h>
+#endif
+
+const char *
+DNBError::AsString() const
+{
+ if (Success())
+ return NULL;
+
+ if (m_str.empty())
+ {
+ const char *s = NULL;
+ switch (m_flavor)
+ {
+ case MachKernel:
+ s = ::mach_error_string (m_err);
+ break;
+
+ case POSIX:
+ s = ::strerror (m_err);
+ break;
+
+#if defined (__arm__)
+ case SpringBoard:
+ {
+ CFStringRef statusStr = SBSApplicationLaunchingErrorString (m_err);
+ if (CFString::UTF8 (statusStr, m_str) == NULL)
+ m_str.clear();
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ if (s)
+ m_str.assign(s);
+ }
+ if (m_str.empty())
+ return NULL;
+ return m_str.c_str();
+}
+
+void
+DNBError::LogThreadedIfError(const char *format, ...) const
+{
+ 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 = AsString();
+ if (err_str == NULL)
+ err_str = "???";
+ DNBLogThreaded ("error: %s err = %s (0x%8.8x)", arg_msg, err_str, m_err);
+ free (arg_msg);
+ }
+ }
+}
+
+void
+DNBError::LogThreaded(const char *format, ...) const
+{
+ 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 = AsString();
+ if (err_str == NULL)
+ err_str = "???";
+ DNBLogThreaded ("error: %s err = %s (0x%8.8x)", arg_msg, err_str, m_err);
+ }
+ else
+ {
+ DNBLogThreaded ("%s err = 0x%8.8x", arg_msg, m_err);
+ }
+ free (arg_msg);
+ }
+}
diff --git a/lldb/tools/debugserver/source/DNBError.h b/lldb/tools/debugserver/source/DNBError.h
new file mode 100644
index 00000000000..10c6638c737
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBError.h
@@ -0,0 +1,96 @@
+//===-- DNBError.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/26/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DNBError_h__
+#define __DNBError_h__
+
+#include <errno.h>
+#include <mach/mach.h>
+#include <stdio.h>
+#include <string>
+
+class DNBError
+{
+public:
+ typedef uint32_t ValueType;
+ typedef enum
+ {
+ Generic = 0,
+ MachKernel,
+ POSIX
+#if defined (__arm__)
+ , SpringBoard
+#endif
+ } FlavorType;
+
+ explicit DNBError( ValueType err = 0,
+ FlavorType flavor = Generic) :
+ m_err(err),
+ m_flavor(flavor)
+ {
+ }
+
+ const char * AsString() const;
+ void Clear() { m_err = 0; m_flavor = Generic; m_str.clear(); }
+ ValueType Error() const { return m_err; }
+ FlavorType Flavor() const { return m_flavor; }
+
+ ValueType operator = (kern_return_t err)
+ {
+ m_err = err;
+ m_flavor = MachKernel;
+ m_str.clear();
+ return m_err;
+ }
+
+ void SetError(kern_return_t err)
+ {
+ m_err = err;
+ m_flavor = MachKernel;
+ m_str.clear();
+ }
+
+ void SetErrorToErrno()
+ {
+ m_err = errno;
+ m_flavor = POSIX;
+ m_str.clear();
+ }
+
+ void SetError(ValueType err, FlavorType flavor)
+ {
+ m_err = err;
+ m_flavor = flavor;
+ m_str.clear();
+ }
+
+ // Generic errors can set their own string values
+ void SetErrorString(const char *err_str)
+ {
+ if (err_str && err_str[0])
+ m_str = err_str;
+ else
+ m_str.clear();
+ }
+ bool Success() const { return m_err == 0; }
+ bool Fail() const { return m_err != 0; }
+ void LogThreadedIfError(const char *format, ...) const;
+ void LogThreaded(const char *format, ...) const;
+protected:
+ ValueType m_err;
+ FlavorType m_flavor;
+ mutable std::string m_str;
+};
+
+
+#endif // #ifndef __DNBError_h__
diff --git a/lldb/tools/debugserver/source/DNBLog.cpp b/lldb/tools/debugserver/source/DNBLog.cpp
new file mode 100644
index 00000000000..d99e415f37e
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBLog.cpp
@@ -0,0 +1,309 @@
+//===-- DNBLog.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/18/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DNBLog.h"
+
+static int g_debug = 0;
+static int g_verbose = 0;
+
+#if defined (DNBLOG_ENABLED)
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <mach/mach.h>
+#include <pthread.h>
+#include "PThreadMutex.h"
+
+uint32_t g_log_bits = 0;
+static DNBCallbackLog g_log_callback = NULL;
+static void *g_log_baton = NULL;
+
+
+int
+DNBLogGetDebug ()
+{
+ return g_debug;
+}
+
+
+void
+DNBLogSetDebug (int g)
+{
+ g_debug = g;
+}
+
+int
+DNBLogGetVerbose ()
+{
+ return g_verbose;
+}
+
+void
+DNBLogSetVerbose (int v)
+{
+ g_verbose = v;
+}
+
+bool
+DNBLogCheckLogBit (uint32_t bit)
+{
+ return (g_log_bits & bit) != 0;
+}
+
+uint32_t
+DNBLogSetLogMask (uint32_t mask)
+{
+ uint32_t old = g_log_bits;
+ g_log_bits = mask;
+ return old;
+}
+
+uint32_t
+DNBLogGetLogMask ()
+{
+ return g_log_bits;
+}
+
+void
+DNBLogSetLogCallback (DNBCallbackLog callback, void *baton)
+{
+ g_log_callback = callback;
+ g_log_baton = baton;
+}
+
+bool
+DNBLogEnabled ()
+{
+ return g_log_callback != NULL;
+}
+
+static inline void
+_DNBLogVAPrintf(uint32_t flags, const char *format, va_list args)
+{
+ if (g_log_callback)
+ g_log_callback(g_log_baton, flags, format, args);
+}
+
+void
+_DNBLog(uint32_t flags, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ _DNBLogVAPrintf(flags, format, args);
+ va_end (args);
+}
+
+//----------------------------------------------------------------------
+// Print debug strings if and only if the global g_debug is set to
+// a non-zero value.
+//----------------------------------------------------------------------
+void
+_DNBLogDebug (const char *format, ...)
+{
+ if (DNBLogEnabled () && g_debug)
+ {
+ va_list args;
+ va_start (args, format);
+ _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG, format, args);
+ va_end (args);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Print debug strings if and only if the global g_debug is set to
+// a non-zero value.
+//----------------------------------------------------------------------
+void
+_DNBLogDebugVerbose (const char *format, ...)
+{
+ if (DNBLogEnabled () && g_debug && g_verbose)
+ {
+ va_list args;
+ va_start (args, format);
+ _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG | DNBLOG_FLAG_VERBOSE, format, args);
+ va_end (args);
+ }
+}
+
+
+static pthread_mutex_t *
+GetLogThreadedMutex()
+{
+ static PThreadMutex g_LogThreadedMutex(PTHREAD_MUTEX_RECURSIVE);
+ return g_LogThreadedMutex.Mutex();
+}
+static uint32_t g_message_id = 0;
+
+//----------------------------------------------------------------------
+// Prefix the formatted log string with process and thread IDs and
+// suffix it with a newline.
+//----------------------------------------------------------------------
+void
+_DNBLogThreaded (const char *format, ...)
+{
+ if (DNBLogEnabled ())
+ {
+ PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex());
+
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ _DNBLog (DNBLOG_FLAG_THREADED, "%u [%4.4x/%4.4x]: %s", ++g_message_id, getpid(), mach_thread_self(), arg_msg);
+ free (arg_msg);
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// Prefix the formatted log string with process and thread IDs and
+// suffix it with a newline.
+//----------------------------------------------------------------------
+void
+_DNBLogThreadedIf (uint32_t log_bit, const char *format, ...)
+{
+ if (DNBLogEnabled () && (log_bit & g_log_bits) == log_bit)
+ {
+ PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex());
+
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ _DNBLog (DNBLOG_FLAG_THREADED, "%u [%4.4x/%4.4x]: %s", ++g_message_id, getpid(), mach_thread_self(), arg_msg);
+ free (arg_msg);
+ }
+ }
+}
+
+
+
+//----------------------------------------------------------------------
+// Printing of errors that are not fatal.
+//----------------------------------------------------------------------
+void
+_DNBLogError (const char *format, ...)
+{
+ if (DNBLogEnabled ())
+ {
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ _DNBLog (DNBLOG_FLAG_ERROR, "error: %s", arg_msg);
+ free (arg_msg);
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// Printing of errors that ARE fatal. Exit with ERR exit code
+// immediately.
+//----------------------------------------------------------------------
+void
+_DNBLogFatalError (int err, const char *format, ...)
+{
+ if (DNBLogEnabled ())
+ {
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ _DNBLog (DNBLOG_FLAG_ERROR | DNBLOG_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
+_DNBLogVerbose (const char *format, ...)
+{
+ if (DNBLogEnabled () && g_verbose)
+ {
+ va_list args;
+ va_start (args, format);
+ _DNBLogVAPrintf(DNBLOG_FLAG_VERBOSE, format, args);
+ va_end (args);
+ }
+}
+
+//----------------------------------------------------------------------
+// Printing of warnings that are not fatal only if verbose mode is
+// enabled.
+//----------------------------------------------------------------------
+void
+_DNBLogWarningVerbose (const char *format, ...)
+{
+ if (DNBLogEnabled () && g_verbose)
+ {
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ _DNBLog (DNBLOG_FLAG_WARNING | DNBLOG_FLAG_VERBOSE, "warning: %s", arg_msg);
+ free (arg_msg);
+ }
+ }
+}
+//----------------------------------------------------------------------
+// Printing of warnings that are not fatal.
+//----------------------------------------------------------------------
+void
+_DNBLogWarning (const char *format, ...)
+{
+ if (DNBLogEnabled ())
+ {
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ _DNBLog (DNBLOG_FLAG_WARNING, "warning: %s", arg_msg);
+ free (arg_msg);
+ }
+ }
+}
+
+#endif
diff --git a/lldb/tools/debugserver/source/DNBLog.h b/lldb/tools/debugserver/source/DNBLog.h
new file mode 100644
index 00000000000..76ce0c55d37
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBLog.h
@@ -0,0 +1,96 @@
+//===-- DNBLog.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/18/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DNBLog_h__
+#define __DNBLog_h__
+
+#include <stdio.h>
+#include <stdint.h>
+#include "DNBDefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Flags that get filled in automatically before calling the log callback function
+#define DNBLOG_FLAG_FATAL (1u << 0)
+#define DNBLOG_FLAG_ERROR (1u << 1)
+#define DNBLOG_FLAG_WARNING (1u << 2)
+#define DNBLOG_FLAG_DEBUG (1u << 3)
+#define DNBLOG_FLAG_VERBOSE (1u << 4)
+#define DNBLOG_FLAG_THREADED (1u << 5)
+
+#define DNBLOG_ENABLED
+
+#if defined (DNBLOG_ENABLED)
+
+#define DNB_EXPORT __attribute__((visibility("default")))
+
+void _DNBLog(uint32_t flags, const char *format, ...) DNB_EXPORT;
+void _DNBLogDebug (const char *fmt, ...) DNB_EXPORT;
+void _DNBLogDebugVerbose (const char *fmt, ...) DNB_EXPORT;
+void _DNBLogThreaded (const char *fmt, ...) DNB_EXPORT;
+void _DNBLogThreadedIf (uint32_t mask, const char *fmt, ...) DNB_EXPORT;
+void _DNBLogError (const char *fmt, ...) DNB_EXPORT;
+void _DNBLogFatalError (int err, const char *fmt, ...) DNB_EXPORT;
+void _DNBLogVerbose (const char *fmt, ...) DNB_EXPORT;
+void _DNBLogWarning (const char *fmt, ...) DNB_EXPORT;
+void _DNBLogWarningVerbose (const char *fmt, ...) DNB_EXPORT;
+bool DNBLogCheckLogBit (uint32_t bit) DNB_EXPORT;
+uint32_t DNBLogSetLogMask (uint32_t mask) DNB_EXPORT;
+uint32_t DNBLogGetLogMask () DNB_EXPORT;
+void DNBLogSetLogCallback (DNBCallbackLog callback, void *baton) DNB_EXPORT;
+bool DNBLogEnabled () DNB_EXPORT;
+int DNBLogGetDebug () DNB_EXPORT;
+void DNBLogSetDebug (int g) DNB_EXPORT;
+int DNBLogGetVerbose () DNB_EXPORT;
+void DNBLogSetVerbose (int g) DNB_EXPORT;
+
+#define DNBLog(fmt, ...) do { if (DNBLogEnabled()) { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
+#define DNBLogDebug(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogDebug(fmt, ## __VA_ARGS__); } } while (0)
+#define DNBLogDebugVerbose(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogDebugVerbose(fmt, ## __VA_ARGS__); } } while (0)
+#define DNBLogThreaded(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogThreaded(fmt, ## __VA_ARGS__); } } while (0)
+#define DNBLogThreadedIf(mask, fmt, ...) do { if (DNBLogEnabled()) { _DNBLogThreadedIf(mask, fmt, ## __VA_ARGS__); } } while (0)
+#define DNBLogError(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogError(fmt, ## __VA_ARGS__); } } while (0)
+#define DNBLogFatalError(err, fmt, ...) do { if (DNBLogEnabled()) { _DNBLogFatalError(err, fmt, ## __VA_ARGS__); } } while (0)
+#define DNBLogVerbose(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogVerbose(fmt, ## __VA_ARGS__); } } while (0)
+#define DNBLogWarning(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogWarning(fmt, ## __VA_ARGS__); } } while (0)
+#define DNBLogWarningVerbose(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogWarningVerbose(fmt, ## __VA_ARGS__); } } while (0)
+
+#else // #if defined(DNBLOG_ENABLED)
+
+#define DNBLogDebug(...) ((void)0)
+#define DNBLogDebugVerbose(...) ((void)0)
+#define DNBLogThreaded(...) ((void)0)
+#define DNBLogThreadedIf(...) ((void)0)
+#define DNBLogError(...) ((void)0)
+#define DNBLogFatalError(...) ((void)0)
+#define DNBLogVerbose(...) ((void)0)
+#define DNBLogWarning(...) ((void)0)
+#define DNBLogWarningVerbose(...) ((void)0)
+#define DNBLogGetLogFile() ((FILE *)NULL)
+#define DNBLogSetLogFile(f) ((void)0)
+#define DNBLogCheckLogBit(bit) ((bool)false)
+#define DNBLogSetLogMask(mask) ((uint32_t)0u)
+#define DNBLogGetLogMask() ((uint32_t)0u)
+#define DNBLogToASL() ((void)0)
+#define DNBLogToFile() ((void)0)
+#define DNBLogCloseLogFile() ((void)0)
+
+#endif // #else defined(DNBLOG_ENABLED)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // #ifndef __DNBLog_h__
diff --git a/lldb/tools/debugserver/source/DNBRegisterInfo.cpp b/lldb/tools/debugserver/source/DNBRegisterInfo.cpp
new file mode 100644
index 00000000000..a8f09bc8784
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBRegisterInfo.cpp
@@ -0,0 +1,220 @@
+//===-- DNBRegisterInfo.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 8/3/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DNBRegisterInfo.h"
+#include "DNBLog.h"
+#include <string.h>
+
+DNBRegisterValueClass::DNBRegisterValueClass(const DNBRegisterInfo *regInfo)
+{
+ Clear();
+ if (regInfo)
+ info = *regInfo;
+}
+
+void
+DNBRegisterValueClass::Clear()
+{
+ memset(&info, 0, sizeof(DNBRegisterInfo));
+ memset(&value, 0, sizeof(value));
+}
+
+bool
+DNBRegisterValueClass::IsValid() const
+{
+ return
+ info.name != NULL &&
+ info.type != InvalidRegType &&
+ info.size > 0 && info.size <= sizeof(value);
+}
+
+#define PRINT_COMMA_SEPARATOR do { if (pos < end) { if (i > 0) { strncpy(pos, ", ", end - pos); pos += 2; } } } while (0)
+
+void
+DNBRegisterValueClass::Dump(const char *pre, const char *post) const
+{
+ if (info.name != NULL)
+ {
+ int i;
+ char str[1024];
+ char *pos;
+ char *end = str + sizeof(str);
+ if (info.format == Hex)
+ {
+ switch (info.size)
+ {
+ case 0: snprintf(str, sizeof(str), "%s", "error: invalid register size of zero."); break;
+ case 1: snprintf(str, sizeof(str), "0x%2.2x", value.uint8); break;
+ case 2: snprintf(str, sizeof(str), "0x%4.4x", value.uint16); break;
+ case 4: snprintf(str, sizeof(str), "0x%8.8x", value.uint32); break;
+ case 8: snprintf(str, sizeof(str), "0x%16.16llx", value.uint64); break;
+ case 16: snprintf(str, sizeof(str), "0x%16.16llx%16.16llx", value.v_uint64[0], value.v_uint64[1]); break;
+ default:
+ strncpy(str, "0x", 3);
+ pos = str + 2;
+ for (i=0; i<info.size; ++i)
+ {
+ if (pos < end)
+ pos += snprintf(pos, end - pos, "%2.2x", (uint32_t)value.v_uint8[i]);
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch (info.type)
+ {
+ case Uint:
+ switch (info.size)
+ {
+ case 1: snprintf(str, sizeof(str), "%u", value.uint8); break;
+ case 2: snprintf(str, sizeof(str), "%u", value.uint16); break;
+ case 4: snprintf(str, sizeof(str), "%u", value.uint32); break;
+ case 8: snprintf(str, sizeof(str), "%llu", value.uint64); break;
+ default: snprintf(str, sizeof(str), "error: unsupported uint byte size %d.", info.size); break;
+ }
+ break;
+
+ case Sint:
+ switch (info.size)
+ {
+ case 1: snprintf(str, sizeof(str), "%d", value.sint8); break;
+ case 2: snprintf(str, sizeof(str), "%d", value.sint16); break;
+ case 4: snprintf(str, sizeof(str), "%d", value.sint32); break;
+ case 8: snprintf(str, sizeof(str), "%lld", value.sint64); break;
+ default: snprintf(str, sizeof(str), "error: unsupported sint byte size %d.", info.size); break;
+ }
+ break;
+
+ case IEEE754:
+ switch (info.size)
+ {
+ case 4: snprintf(str, sizeof(str), "%f", value.float32); break;
+ case 8: snprintf(str, sizeof(str), "%g", value.float64); break;
+ default: snprintf(str, sizeof(str), "error: unsupported float byte size %d.", info.size); break;
+ }
+ break;
+
+ case Vector:
+ if (info.size > 0)
+ {
+ switch (info.format)
+ {
+ case VectorOfSInt8:
+ snprintf(str, sizeof(str), "%s", "sint8 { ");
+ pos = str + strlen(str);
+ for (i=0; i<info.size; ++i)
+ {
+ PRINT_COMMA_SEPARATOR;
+ if (pos < end)
+ pos += snprintf(pos, end - pos, "%d", (int32_t)value.v_sint8[i]);
+ }
+ strncat(str, " }", sizeof(str));
+ break;
+
+ default:
+ DNBLogError("unsupported vector format %d, defaulting to hex bytes.", info.format);
+ case VectorOfUInt8:
+ snprintf(str, sizeof(str), "%s", "uint8 { ");
+ pos = str + strlen(str);
+ for (i=0; i<info.size; ++i)
+ {
+ PRINT_COMMA_SEPARATOR;
+ if (pos < end)
+ pos += snprintf(pos, end - pos, "%u", (uint32_t)value.v_uint8[i]);
+ }
+ break;
+
+ case VectorOfSInt16:
+ snprintf(str, sizeof(str), "%s", "sint16 { ");
+ pos = str + strlen(str);
+ for (i=0; i<info.size/2; ++i)
+ {
+ PRINT_COMMA_SEPARATOR;
+ if (pos < end)
+ pos += snprintf(pos, end - pos, "%d", (int32_t)value.v_sint16[i]);
+ }
+ break;
+
+ case VectorOfUInt16:
+ snprintf(str, sizeof(str), "%s", "uint16 { ");
+ pos = str + strlen(str);
+ for (i=0; i<info.size/2; ++i)
+ {
+ PRINT_COMMA_SEPARATOR;
+ if (pos < end)
+ pos += snprintf(pos, end - pos, "%u", (uint32_t)value.v_uint16[i]);
+ }
+ break;
+
+ case VectorOfSInt32:
+ snprintf(str, sizeof(str), "%s", "sint32 { ");
+ pos = str + strlen(str);
+ for (i=0; i<info.size/4; ++i)
+ {
+ PRINT_COMMA_SEPARATOR;
+ if (pos < end)
+ pos += snprintf(pos, end - pos, "%d", (int32_t)value.v_sint32[i]);
+ }
+ break;
+
+ case VectorOfUInt32:
+ snprintf(str, sizeof(str), "%s", "uint32 { ");
+ pos = str + strlen(str);
+ for (i=0; i<info.size/4; ++i)
+ {
+ PRINT_COMMA_SEPARATOR;
+ if (pos < end)
+ pos += snprintf(pos, end - pos, "%u", (uint32_t)value.v_uint32[i]);
+ }
+ break;
+
+ case VectorOfFloat32:
+ snprintf(str, sizeof(str), "%s", "float32 { ");
+ pos = str + strlen(str);
+ for (i=0; i<info.size/4; ++i)
+ {
+ PRINT_COMMA_SEPARATOR;
+ if (pos < end)
+ pos += snprintf(pos, end - pos, "%f", value.v_float32[i]);
+ }
+ break;
+
+ case VectorOfUInt128:
+ snprintf(str, sizeof(str), "%s", "uint128 { ");
+ pos = str + strlen(str);
+ for (i=0; i<info.size/16; ++i)
+ {
+ PRINT_COMMA_SEPARATOR;
+ if (pos < end)
+ pos += snprintf(pos, end - pos, "0x%16.16llx%16.16llx", value.v_uint64[i], value.v_uint64[i+1]);
+ }
+ break;
+ }
+ strncat(str, " }", sizeof(str));
+ }
+ else
+ {
+ snprintf(str, sizeof(str), "error: unsupported vector size %d.", info.size);
+ }
+ break;
+
+ default:
+ snprintf(str, sizeof(str), "error: unsupported register type %d.", info.type);
+ break;
+ }
+ }
+
+ DNBLog("%s%4s = %s%s", pre ? pre : "", info.name, str, post ? post : "");
+ }
+}
diff --git a/lldb/tools/debugserver/source/DNBRegisterInfo.h b/lldb/tools/debugserver/source/DNBRegisterInfo.h
new file mode 100644
index 00000000000..666c397e0b5
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBRegisterInfo.h
@@ -0,0 +1,31 @@
+//===-- DNBRegisterInfo.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 8/3/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DNBRegisterInfo_h__
+#define __DNBRegisterInfo_h__
+
+#include <stdint.h>
+#include <stdio.h>
+#include "DNBDefs.h"
+
+struct DNBRegisterValueClass : public DNBRegisterValue
+{
+#ifdef __cplusplus
+ DNBRegisterValueClass(const DNBRegisterInfo *regInfo = NULL);
+ void Clear();
+ void Dump(const char *pre, const char *post) const;
+ bool IsValid() const;
+#endif
+};
+
+#endif
diff --git a/lldb/tools/debugserver/source/DNBRuntimeAction.h b/lldb/tools/debugserver/source/DNBRuntimeAction.h
new file mode 100644
index 00000000000..d77bda8c604
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBRuntimeAction.h
@@ -0,0 +1,25 @@
+//===-- DNBRuntimeAction.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 10/8/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DNBRuntimeAction_h__
+#define __DNBRuntimeAction_h__
+
+class DNBRuntimeAction
+{
+ virtual void Initialize (nub_process_t pid) = 0;
+ virtual void ProcessStateChanged (nub_state_t state) = 0;
+ virtual void SharedLibraryStateChanged (DNBExecutableImageInfo *image_infos, nub_size_t num_image_infos) = 0;
+};
+
+
+#endif // #ifndef __DNBRuntimeAction_h__
diff --git a/lldb/tools/debugserver/source/DNBThreadResumeActions.cpp b/lldb/tools/debugserver/source/DNBThreadResumeActions.cpp
new file mode 100644
index 00000000000..b50dd061784
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBThreadResumeActions.cpp
@@ -0,0 +1,116 @@
+//===-- DNBThreadResumeActions.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 03/13/2010
+//
+//===----------------------------------------------------------------------===//
+
+#include "DNBThreadResumeActions.h"
+
+DNBThreadResumeActions::DNBThreadResumeActions() :
+ m_actions (),
+ m_signal_handled ()
+{
+}
+
+DNBThreadResumeActions::DNBThreadResumeActions (const DNBThreadResumeAction *actions, size_t num_actions) :
+ m_actions (),
+ m_signal_handled ()
+{
+ if (actions && num_actions)
+ {
+ m_actions.assign (actions, actions + num_actions);
+ m_signal_handled.assign (num_actions, false);
+ }
+}
+
+DNBThreadResumeActions::DNBThreadResumeActions (nub_state_t default_action, int signal) :
+ m_actions(),
+ m_signal_handled ()
+{
+ SetDefaultThreadActionIfNeeded (default_action, signal);
+}
+
+void
+DNBThreadResumeActions::Append (const DNBThreadResumeAction &action)
+{
+ m_actions.push_back (action);
+ m_signal_handled.push_back (false);
+}
+
+void
+DNBThreadResumeActions::AppendAction
+(
+ nub_thread_t tid,
+ nub_state_t state,
+ int signal,
+ nub_addr_t addr
+)
+{
+ DNBThreadResumeAction action = { tid, state, signal, addr };
+ Append (action);
+}
+
+
+const DNBThreadResumeAction *
+DNBThreadResumeActions::GetActionForThread (nub_thread_t tid, bool default_ok) const
+{
+ const size_t num_actions = m_actions.size();
+ for (size_t i=0; i<num_actions; ++i)
+ {
+ if (m_actions[i].tid == tid)
+ return &m_actions[i];
+ }
+ if (default_ok && tid != INVALID_NUB_THREAD)
+ return GetActionForThread (INVALID_NUB_THREAD, false);
+ return NULL;
+}
+
+size_t
+DNBThreadResumeActions::NumActionsWithState (nub_state_t state) const
+{
+ size_t count = 0;
+ const size_t num_actions = m_actions.size();
+ for (size_t i=0; i<num_actions; ++i)
+ {
+ if (m_actions[i].state == state)
+ ++count;
+ }
+ return count;
+}
+
+
+bool
+DNBThreadResumeActions::SetDefaultThreadActionIfNeeded (nub_state_t action, int signal)
+{
+ if (GetActionForThread (INVALID_NUB_THREAD, true) == NULL)
+ {
+ // There isn't a default action so we do need to set it.
+ DNBThreadResumeAction default_action = {INVALID_NUB_THREAD, action, signal, INVALID_NUB_ADDRESS };
+ m_actions.push_back (default_action);
+ m_signal_handled.push_back (false);
+ return true; // Return true as we did add the default action
+ }
+ return false;
+}
+
+
+void
+DNBThreadResumeActions::SetSignalHandledForThread (nub_thread_t tid) const
+{
+ if (tid != INVALID_NUB_THREAD)
+ {
+ const size_t num_actions = m_actions.size();
+ for (size_t i=0; i<num_actions; ++i)
+ {
+ if (m_actions[i].tid == tid)
+ m_signal_handled[i] = true;
+ }
+ }
+}
diff --git a/lldb/tools/debugserver/source/DNBThreadResumeActions.h b/lldb/tools/debugserver/source/DNBThreadResumeActions.h
new file mode 100644
index 00000000000..f3fb8de6a82
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBThreadResumeActions.h
@@ -0,0 +1,95 @@
+//===-- DNBThreadResumeActions.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 03/13/2010
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef __DNBThreadResumeActions_h__
+#define __DNBThreadResumeActions_h__
+
+#include <vector>
+
+#include "DNBDefs.h"
+
+
+class DNBThreadResumeActions
+{
+public:
+ DNBThreadResumeActions ();
+
+ DNBThreadResumeActions (nub_state_t default_action, int signal);
+
+ DNBThreadResumeActions (const DNBThreadResumeAction *actions, size_t num_actions);
+
+ bool
+ IsEmpty() const
+ {
+ return m_actions.empty();
+ }
+
+ void
+ Append (const DNBThreadResumeAction &action);
+
+ void
+ AppendAction (nub_thread_t tid,
+ nub_state_t state,
+ int signal = 0,
+ nub_addr_t addr = INVALID_NUB_ADDRESS);
+
+ void
+ AppendResumeAll ()
+ {
+ AppendAction (INVALID_NUB_THREAD, eStateRunning);
+ }
+
+ void
+ AppendSuspendAll ()
+ {
+ AppendAction (INVALID_NUB_THREAD, eStateStopped);
+ }
+
+ void
+ AppendStepAll ()
+ {
+ AppendAction (INVALID_NUB_THREAD, eStateStepping);
+ }
+
+ const DNBThreadResumeAction *
+ GetActionForThread (nub_thread_t tid, bool default_ok) const;
+
+ size_t
+ NumActionsWithState (nub_state_t state) const;
+
+ bool
+ SetDefaultThreadActionIfNeeded (nub_state_t action, int signal);
+
+ void
+ SetSignalHandledForThread (nub_thread_t tid) const;
+
+ const DNBThreadResumeAction *
+ GetFirst() const
+ {
+ return m_actions.data();
+ }
+
+ size_t
+ GetSize () const
+ {
+ return m_actions.size();
+ }
+
+protected:
+ std::vector<DNBThreadResumeAction> m_actions;
+ mutable std::vector<bool> m_signal_handled;
+};
+
+
+#endif // #ifndef __DNBThreadResumeActions_h__
diff --git a/lldb/tools/debugserver/source/DNBTimer.h b/lldb/tools/debugserver/source/DNBTimer.h
new file mode 100644
index 00000000000..a78b80f606d
--- /dev/null
+++ b/lldb/tools/debugserver/source/DNBTimer.h
@@ -0,0 +1,162 @@
+//===-- DNBTimer.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 12/13/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DNBTimer_h__
+#define __DNBTimer_h__
+
+#include <sys/time.h>
+#include <stdint.h>
+#include <memory>
+#include "PThreadMutex.h"
+
+class DNBTimer
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ DNBTimer (bool threadSafe) :
+ m_mutexAP()
+ {
+ if (threadSafe)
+ m_mutexAP.reset(new PThreadMutex(PTHREAD_MUTEX_RECURSIVE));
+ Reset();
+ }
+
+ DNBTimer (const DNBTimer& rhs) :
+ m_mutexAP()
+ {
+ // Create a new mutex to make this timer thread safe as well if
+ // the timer we are copying is thread safe
+ if (rhs.IsThreadSafe())
+ m_mutexAP.reset(new PThreadMutex(PTHREAD_MUTEX_RECURSIVE));
+ m_timeval = rhs.m_timeval;
+ }
+
+ DNBTimer& operator= (const DNBTimer& rhs)
+ {
+ // Create a new mutex to make this timer thread safe as well if
+ // the timer we are copying is thread safe
+ if (rhs.IsThreadSafe())
+ m_mutexAP.reset(new PThreadMutex(PTHREAD_MUTEX_RECURSIVE));
+ m_timeval = rhs.m_timeval;
+ return *this;
+ }
+
+ ~DNBTimer ()
+ {
+ }
+
+ bool
+ IsThreadSafe() const
+ {
+ return m_mutexAP.get() != NULL;
+ }
+ //------------------------------------------------------------------
+ // Reset the time value to now
+ //------------------------------------------------------------------
+ void
+ Reset ()
+ {
+ PTHREAD_MUTEX_LOCKER (locker, m_mutexAP.get());
+ gettimeofday (&m_timeval, NULL);
+ }
+ //------------------------------------------------------------------
+ // Get the total mircoseconds since Jan 1, 1970
+ //------------------------------------------------------------------
+ uint64_t
+ TotalMicroSeconds () const
+ {
+ PTHREAD_MUTEX_LOCKER (locker, m_mutexAP.get());
+ return (uint64_t)(m_timeval.tv_sec) * 1000000ull + (uint64_t)m_timeval.tv_usec;
+ }
+
+ void
+ GetTime (uint32_t& sec, uint32_t& usec) const
+ {
+ PTHREAD_MUTEX_LOCKER (locker, m_mutexAP.get());
+ sec = m_timeval.tv_sec;
+ usec = m_timeval.tv_usec;
+ }
+ //------------------------------------------------------------------
+ // Return the number of microseconds elapsed between now and the
+ // m_timeval
+ //------------------------------------------------------------------
+ uint64_t
+ ElapsedMicroSeconds (bool update)
+ {
+ PTHREAD_MUTEX_LOCKER (locker, m_mutexAP.get());
+ struct timeval now;
+ gettimeofday (&now, NULL);
+ uint64_t now_usec = (uint64_t)(now.tv_sec) * 1000000ull + (uint64_t)now.tv_usec;
+ uint64_t this_usec = (uint64_t)(m_timeval.tv_sec) * 1000000ull + (uint64_t)m_timeval.tv_usec;
+ uint64_t elapsed = now_usec - this_usec;
+ // Update the timer time value if requeseted
+ if (update)
+ m_timeval = now;
+ return elapsed;
+ }
+
+ static uint64_t GetTimeOfDay()
+ {
+ struct timeval now;
+ gettimeofday (&now, NULL);
+ uint64_t now_usec = (uint64_t)(now.tv_sec) * 1000000ull + (uint64_t)now.tv_usec;
+ return now_usec;
+ }
+
+ static void OffsetTimeOfDay (struct timespec* ts, __darwin_time_t sec_offset = 0, long nsec_offset = 0)
+ {
+ if (ts == NULL)
+ return;
+ // Get the current time in a timeval structure
+ struct timeval now;
+ gettimeofday (&now, NULL);
+ // Morph it into a timespec
+ TIMEVAL_TO_TIMESPEC(&now, ts);
+ // Offset the timespec if requested
+ if (sec_offset != 0 || nsec_offset != 0)
+ {
+ // Offset the nano seconds
+ ts->tv_nsec += nsec_offset;
+ // Offset the seconds taking into account a nano-second overflow
+ ts->tv_sec = ts->tv_sec + ts->tv_nsec / 1000000000 + sec_offset;
+ // Trim the nanoseconds back there was an overflow
+ ts->tv_nsec = ts->tv_nsec % 1000000000;
+ }
+ }
+ static bool TimeOfDayLaterThan (struct timespec &ts)
+ {
+ struct timespec now;
+ OffsetTimeOfDay(&now);
+ if (now.tv_sec > ts.tv_sec)
+ return true;
+ else if (now.tv_sec < ts.tv_sec)
+ return false;
+ else
+ {
+ if (now.tv_nsec > ts.tv_nsec)
+ return true;
+ else
+ return false;
+ }
+ }
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from DNBTimer can see and modify these
+ //------------------------------------------------------------------
+ std::auto_ptr<PThreadMutex> m_mutexAP;
+ struct timeval m_timeval;
+};
+
+#endif // #ifndef __DNBTimer_h__
diff --git a/lldb/tools/debugserver/source/FunctionProfiler.cpp b/lldb/tools/debugserver/source/FunctionProfiler.cpp
new file mode 100644
index 00000000000..2fa57d3a770
--- /dev/null
+++ b/lldb/tools/debugserver/source/FunctionProfiler.cpp
@@ -0,0 +1,288 @@
+//===-- FunctionProfiler.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 10/8/08.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FunctionProfiler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "DNB.h"
+
+// Project includes
+
+//----------------------------------------------------------------------
+// FunctionProfiler constructor
+//----------------------------------------------------------------------
+FunctionProfiler::FunctionProfiler(nub_addr_t start_addr, nub_addr_t stop_addr) :
+ m_pid(INVALID_NUB_PROCESS),
+ m_start_addr(start_addr),
+ m_stop_addr(stop_addr),
+ m_start_break_id(INVALID_NUB_BREAK_ID),
+ m_stop_break_id(INVALID_NUB_BREAK_ID),
+ m_func_entered_count(0),
+ m_last_pc(0),
+ m_last_flags(0),
+ m_consecutive_opcode_count(0),
+ m_total_opcode_count(0)
+{
+}
+
+
+FunctionProfiler::~FunctionProfiler()
+{
+ Clear();
+}
+
+
+void
+FunctionProfiler::Clear()
+{
+ if (m_pid != INVALID_NUB_PROCESS)
+ {
+ if (m_start_break_id != INVALID_NUB_BREAK_ID)
+ DNBBreakpointClear(m_pid, m_start_break_id);
+ if (m_stop_break_id != INVALID_NUB_BREAK_ID)
+ DNBBreakpointClear(m_pid, m_stop_break_id);
+ }
+ m_start_break_id = INVALID_NUB_BREAK_ID;
+ m_stop_break_id = INVALID_NUB_BREAK_ID;
+ m_func_entered_count = 0;
+ m_last_pc = 0;
+ m_last_flags = 0;
+ m_consecutive_opcode_count = 0;
+}
+
+void
+FunctionProfiler::Initialize(nub_process_t pid)
+{
+ //printf("FunctionProfiler::%s(0x%4.4x)\n", __FUNCTION__, pid);
+ Clear();
+ m_pid = pid;
+}
+
+#include "DNBDataRef.h"
+
+void
+FunctionProfiler::SetBreakpoints()
+{
+#if defined (__i386__)
+ nub_size_t bp_opcode_size = 1;
+#elif defined (__powerpc__) || defined (__ppc__)
+ nub_size_t bp_opcode_size = 4;
+#endif
+ if (m_start_addr != INVALID_NUB_ADDRESS && !NUB_BREAK_ID_IS_VALID(m_start_break_id))
+ {
+#if defined (__arm__)
+ m_start_break_id = DNBBreakpointSet(m_pid, m_start_addr & 0xFFFFFFFEu, m_start_addr & 1 ? 2 : 4, false);
+#else
+ m_start_break_id = DNBBreakpointSet(m_pid, m_start_addr, bp_opcode_size, false);
+#endif
+ if (NUB_BREAK_ID_IS_VALID(m_start_break_id))
+ DNBBreakpointSetCallback(m_pid, m_start_break_id, FunctionProfiler::BreakpointHitCallback, this);
+ }
+ if (m_stop_addr != INVALID_NUB_ADDRESS && !NUB_BREAK_ID_IS_VALID(m_stop_break_id))
+ {
+#if defined (__arm__)
+ m_stop_break_id = DNBBreakpointSet(m_pid, m_stop_addr & 0xFFFFFFFEu, m_stop_addr & 1 ? 2 : 4, false);
+#else
+ m_stop_break_id = DNBBreakpointSet(m_pid, m_stop_addr, bp_opcode_size, false);
+#endif
+ if (NUB_BREAK_ID_IS_VALID(m_stop_break_id))
+ DNBBreakpointSetCallback(m_pid, m_stop_break_id, FunctionProfiler::BreakpointHitCallback, this);
+ }
+}
+
+nub_bool_t
+FunctionProfiler::BreakpointHitCallback(nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton)
+{
+ printf("FunctionProfiler::%s(pid = %4.4x, tid = %4.4x, breakID = %u, baton = %p)\n", __FUNCTION__, pid, tid, breakID, baton);
+ return ((FunctionProfiler*) baton)->BreakpointHit(pid, tid, breakID);
+}
+
+nub_bool_t
+FunctionProfiler::BreakpointHit(nub_process_t pid, nub_thread_t tid, nub_break_t breakID)
+{
+ printf("FunctionProfiler::%s(pid = %4.4x, tid = %4.4x, breakID = %u)\n", __FUNCTION__, pid, tid, breakID);
+ if (breakID == m_start_break_id)
+ {
+ m_func_entered_count++;
+ printf("FunctionProfiler::%s(pid = %4.4x, tid = %4.4x, breakID = %u) START breakpoint hit (%u)\n", __FUNCTION__, pid, tid, breakID, m_func_entered_count);
+ }
+ else if (breakID == m_stop_break_id)
+ {
+ if (m_func_entered_count > 0)
+ m_func_entered_count--;
+ printf("FunctionProfiler::%s(pid = %4.4x, tid = %4.4x, breakID = %u) STOP breakpoint hit (%u)\n", __FUNCTION__, pid, tid, breakID, m_func_entered_count);
+ }
+ return true;
+}
+
+void
+FunctionProfiler::ProcessStateChanged(nub_state_t state)
+{
+// printf("FunctionProfiler::%s(%s)\n", __FUNCTION__, DNBStateAsString(state));
+
+ switch (state)
+ {
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateAttaching:
+ case eStateLaunching:
+ break;
+
+ case eStateDetached:
+ case eStateExited:
+ // No sense is clearing out breakpoints if our process has exited...
+ m_start_break_id = INVALID_NUB_BREAK_ID;
+ m_stop_break_id = INVALID_NUB_BREAK_ID;
+ printf("[0x%8.8x - 0x%8.8x) executed %u total opcodes.\n", m_total_opcode_count);
+ break;
+
+ case eStateStopped:
+ // Keep trying find dyld each time we stop until we do
+ if (!NUB_BREAK_ID_IS_VALID(m_start_break_id))
+ SetBreakpoints();
+
+ if (ShouldStepProcess())
+ {
+
+ // TODO: do logging/tracing here
+ nub_thread_t tid = DNBProcessGetCurrentThread(m_pid);
+ DNBRegisterValue reg;
+ m_total_opcode_count++;
+
+ if (DNBThreadGetRegisterValueByID(m_pid, tid, REGISTER_SET_GENERIC, GENERIC_REGNUM_PC, &reg))
+ {
+ const nub_addr_t pc = reg.value.uint32;
+
+#if defined (__i386__)
+ uint8_t buf[16];
+ uint32_t bytes_read = DNBProcessMemoryRead(m_pid, pc, 1, buf);
+ if (bytes_read == 1)
+ printf("0x%8.8x: %2.2x\n", pc, buf[0]);
+ else
+ printf("0x%8.8x: error: can't read opcode byte.\n", pc);
+
+// if (bytes_read > 0)
+// {
+// for (uint32_t i=0; i<bytes_read; ++i)
+// {
+// printf(" %2.2x", buf[i]);
+// }
+// }
+// printf("\n");
+
+#elif defined (__powerpc__) || defined (__ppc__)
+
+ uint32_t opcode = 0;
+ if (DNBProcessMemoryRead(m_pid, pc, 4, &opcode) == 4)
+ {
+ printf("0x%8.8x: 0x%8.8x\n", pc, opcode);
+ }
+
+#elif defined (__arm__)
+ #define CPSR_T (1u << 5)
+ // Read the CPSR into flags
+ if (DNBThreadGetRegisterValueByID(m_pid, tid, REGISTER_SET_GENERIC, GENERIC_REGNUM_FLAGS, &reg))
+ {
+ const uint32_t flags = reg.value.uint32;
+
+ const bool curr_pc_is_thumb = (flags & CPSR_T) != 0; // check the CPSR T bit
+ const bool last_pc_was_thumb = (m_last_flags & CPSR_T) != 0; // check the CPSR T bit
+ bool opcode_is_sequential = false;
+
+ uint32_t opcode;
+ // Always read four bytes for the opcode
+ if (DNBProcessMemoryRead(m_pid, pc, 4, &opcode) == 4)
+ {
+ if (curr_pc_is_thumb)
+ {
+ // Trim off the high 16 bits if this is a 16 bit thumb instruction
+ if ((opcode & 0xe000) != 0xe000 || (opcode & 0x1800) == 0)
+ {
+ opcode &= 0xFFFFu;
+ printf("0x%8.8x: %4.4x Thumb\n", pc, opcode);
+ }
+ else
+ printf("0x%8.8x: %8.8x Thumb\n", pc, opcode);
+ }
+ else
+ printf("0x%8.8x: %8.8x ARM\n", pc, opcode);
+ }
+
+ if (m_last_flags != 0 && curr_pc_is_thumb == last_pc_was_thumb)
+ {
+ if (curr_pc_is_thumb)
+ {
+ if (pc == m_last_pc + 2)
+ {
+ opcode_is_sequential = true;
+ }
+ else if (pc == m_last_pc + 4)
+ {
+ // Check for 32 bit thumb instruction...
+ uint16_t opcode16;
+ if (DNBProcessMemoryRead(m_pid, m_last_pc, 2, &opcode16) == 2)
+ {
+ if ((opcode16 & 0xe000) == 0xe000 && (opcode16 & 0x1800) != 0)
+ {
+ // Last opcode was a 32 bit thumb instruction...
+ opcode_is_sequential = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (pc == m_last_pc + 4)
+ {
+ opcode_is_sequential = true;
+ }
+ }
+ }
+
+
+ if (opcode_is_sequential)
+ {
+ m_consecutive_opcode_count++;
+ }
+ else
+ {
+ if (m_consecutive_opcode_count > 0)
+ {
+ // printf(" x %u\n", m_consecutive_opcode_count);
+ }
+ m_consecutive_opcode_count = 1;
+ //printf("0x%8.8x: %-5s", pc, curr_pc_is_thumb ? "Thumb" : "ARM");
+ //fflush(stdout);
+ }
+ m_last_flags = flags;
+ }
+#else
+#error undefined architecture
+#endif
+ m_last_pc = pc;
+ }
+ }
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ case eStateCrashed:
+ case eStateSuspended:
+ break;
+
+ default:
+ break;
+ }
+}
diff --git a/lldb/tools/debugserver/source/FunctionProfiler.h b/lldb/tools/debugserver/source/FunctionProfiler.h
new file mode 100644
index 00000000000..a6620560673
--- /dev/null
+++ b/lldb/tools/debugserver/source/FunctionProfiler.h
@@ -0,0 +1,70 @@
+//===-- FunctionProfiler.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 10/8/08.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __FunctionProfiler_h__
+#define __FunctionProfiler_h__
+
+// C Includes
+
+// C++ Includes
+#include <map>
+#include <vector>
+#include <string>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "DNBDefs.h"
+#include "DNBRuntimeAction.h"
+#include "PThreadMutex.h"
+
+class DNBBreakpoint;
+class MachProcess;
+
+class FunctionProfiler : public DNBRuntimeAction
+{
+public:
+ FunctionProfiler (nub_addr_t start_addr, nub_addr_t stop_addr);
+ virtual ~FunctionProfiler ();
+
+ //------------------------------------------------------------------
+ // DNBRuntimeAction required functions
+ //------------------------------------------------------------------
+ virtual void Initialize(nub_process_t pid);
+ virtual void ProcessStateChanged(nub_state_t state);
+ virtual void SharedLibraryStateChanged(DNBExecutableImageInfo *image_infos, nub_size_t num_image_infos) {}
+
+ nub_bool_t BreakpointHit(nub_process_t pid, nub_thread_t tid, nub_break_t breakID);
+ bool ShouldStepProcess() const
+ {
+ return m_func_entered_count > 0;
+ }
+protected:
+ static nub_bool_t BreakpointHitCallback (nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton);
+ void Clear();
+ void SetBreakpoints();
+
+ nub_process_t m_pid;
+ nub_addr_t m_start_addr;
+ nub_addr_t m_stop_addr;
+ nub_break_t m_start_break_id;
+ nub_break_t m_stop_break_id;
+ uint32_t m_func_entered_count;
+ nub_addr_t m_last_pc;
+ uint32_t m_last_flags;
+ uint32_t m_consecutive_opcode_count;
+ uint32_t m_total_opcode_count;
+};
+
+
+#endif // __FunctionProfiler_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/CFBundle.cpp b/lldb/tools/debugserver/source/MacOSX/CFBundle.cpp
new file mode 100644
index 00000000000..a15755044c3
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/CFBundle.cpp
@@ -0,0 +1,87 @@
+//===-- CFBundle.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 1/16/08.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFBundle.h"
+#include "CFString.h"
+
+//----------------------------------------------------------------------
+// CFBundle constructor
+//----------------------------------------------------------------------
+CFBundle::CFBundle(const char *path) :
+ CFReleaser<CFBundleRef>(),
+ m_bundle_url()
+{
+ if (path && path[0])
+ SetPath(path);
+}
+
+//----------------------------------------------------------------------
+// CFBundle copy constructor
+//----------------------------------------------------------------------
+CFBundle::CFBundle(const CFBundle& rhs) :
+ CFReleaser<CFBundleRef>(rhs),
+ m_bundle_url(rhs.m_bundle_url)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFBundle copy constructor
+//----------------------------------------------------------------------
+CFBundle&
+CFBundle::operator=(const CFBundle& rhs)
+{
+ *this = rhs;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFBundle::~CFBundle()
+{
+}
+
+//----------------------------------------------------------------------
+// Set the path for a bundle by supplying a
+//----------------------------------------------------------------------
+bool
+CFBundle::SetPath (const char *path)
+{
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+ // Release our old bundle and ULR
+ reset(); // This class is a CFReleaser<CFBundleRef>
+ m_bundle_url.reset();
+ // Make a CFStringRef from the supplied path
+ CFString cf_path;
+ cf_path.SetFileSystemRepresentation(path);
+ if (cf_path.get())
+ {
+ // Make our Bundle URL
+ m_bundle_url.reset (::CFURLCreateWithFileSystemPath (alloc, cf_path.get(), kCFURLPOSIXPathStyle, true));
+ if (m_bundle_url.get())
+ {
+ reset (::CFBundleCreate (alloc, m_bundle_url.get()));
+ }
+ }
+ return get() != NULL;
+}
+
+CFStringRef
+CFBundle::GetIdentifier () const
+{
+ CFBundleRef bundle = get();
+ if (bundle != NULL)
+ return ::CFBundleGetIdentifier (bundle);
+ return NULL;
+}
diff --git a/lldb/tools/debugserver/source/MacOSX/CFBundle.h b/lldb/tools/debugserver/source/MacOSX/CFBundle.h
new file mode 100644
index 00000000000..d980c0ba16f
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/CFBundle.h
@@ -0,0 +1,37 @@
+//===-- CFBundle.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 1/16/08.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CFBundle_h__
+#define __CFBundle_h__
+
+#include "CFUtils.h"
+
+class CFBundle : public CFReleaser<CFBundleRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFBundle(const char *path = NULL);
+ CFBundle(const CFBundle& rhs);
+ CFBundle& operator=(const CFBundle& rhs);
+ virtual ~CFBundle();
+
+ bool SetPath (const char *path);
+ CFStringRef GetIdentifier () const;
+
+protected:
+ CFReleaser<CFURLRef> m_bundle_url;
+};
+
+#endif // #ifndef __CFBundle_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/CFData.cpp b/lldb/tools/debugserver/source/MacOSX/CFData.cpp
new file mode 100644
index 00000000000..94c93da544a
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/CFData.cpp
@@ -0,0 +1,85 @@
+//===-- CFData.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 1/16/08.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFData.h"
+
+//----------------------------------------------------------------------
+// CFData constructor
+//----------------------------------------------------------------------
+CFData::CFData(CFDataRef data) :
+ CFReleaser<CFDataRef>(data)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFData copy constructor
+//----------------------------------------------------------------------
+CFData::CFData(const CFData& rhs) :
+ CFReleaser<CFDataRef>(rhs)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFData copy constructor
+//----------------------------------------------------------------------
+CFData&
+CFData::operator=(const CFData& rhs)
+
+{
+ *this = rhs;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFData::~CFData()
+{
+}
+
+
+CFIndex
+CFData::GetLength() const
+{
+ CFDataRef data = get();
+ if (data)
+ return CFDataGetLength (data);
+ return 0;
+}
+
+
+const uint8_t*
+CFData::GetBytePtr() const
+{
+ CFDataRef data = get();
+ if (data)
+ return CFDataGetBytePtr (data);
+ return NULL;
+}
+
+CFDataRef
+CFData::Serialize(CFPropertyListRef plist, CFPropertyListFormat format)
+{
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+ reset();
+ CFReleaser<CFWriteStreamRef> stream (::CFWriteStreamCreateWithAllocatedBuffers (alloc, alloc));
+ ::CFWriteStreamOpen (stream.get());
+ CFIndex len = ::CFPropertyListWriteToStream (plist, stream.get(), format, NULL);
+ if (len > 0)
+ reset((CFDataRef)::CFWriteStreamCopyProperty (stream.get(), kCFStreamPropertyDataWritten));
+ ::CFWriteStreamClose (stream.get());
+ return get();
+}
+
diff --git a/lldb/tools/debugserver/source/MacOSX/CFData.h b/lldb/tools/debugserver/source/MacOSX/CFData.h
new file mode 100644
index 00000000000..2c9d65d3af7
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/CFData.h
@@ -0,0 +1,39 @@
+//===-- CFData.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 1/16/08.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CFData_h__
+#define __CFData_h__
+
+#include "CFUtils.h"
+
+class CFData : public CFReleaser<CFDataRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFData(CFDataRef data = NULL);
+ CFData(const CFData& rhs);
+ CFData& operator=(const CFData& rhs);
+ virtual ~CFData();
+
+ CFDataRef Serialize(CFPropertyListRef plist, CFPropertyListFormat format);
+ const uint8_t* GetBytePtr () const;
+ CFIndex GetLength () const;
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from CFData can see and modify these
+ //------------------------------------------------------------------
+};
+
+#endif // #ifndef __CFData_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/CFString.cpp b/lldb/tools/debugserver/source/MacOSX/CFString.cpp
new file mode 100644
index 00000000000..819024ca3bc
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/CFString.cpp
@@ -0,0 +1,201 @@
+//===-- CFString.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 1/16/08.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFString.h"
+#include <string>
+#include <glob.h>
+
+//----------------------------------------------------------------------
+// CFString constructor
+//----------------------------------------------------------------------
+CFString::CFString(CFStringRef s) :
+ CFReleaser<CFStringRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFString copy constructor
+//----------------------------------------------------------------------
+CFString::CFString(const CFString& rhs) :
+ CFReleaser<CFStringRef> (rhs)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFString copy constructor
+//----------------------------------------------------------------------
+CFString&
+CFString::operator=(const CFString& rhs)
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+CFString::CFString (const char *cstr, CFStringEncoding cstr_encoding) :
+ CFReleaser<CFStringRef> ()
+{
+ if (cstr && cstr[0])
+ {
+ reset(::CFStringCreateWithCString(kCFAllocatorDefault, cstr, cstr_encoding));
+ }
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFString::~CFString()
+{
+}
+
+const char *
+CFString::GetFileSystemRepresentation(std::string& s)
+{
+ return CFString::FileSystemRepresentation(get(), s);
+}
+
+CFStringRef
+CFString::SetFileSystemRepresentation (const char *path)
+{
+ CFStringRef new_value = NULL;
+ if (path && path[0])
+ new_value = ::CFStringCreateWithFileSystemRepresentation (kCFAllocatorDefault, path);
+ reset(new_value);
+ return get();
+}
+
+
+CFStringRef
+CFString::SetFileSystemRepresentationFromCFType (CFTypeRef cf_type)
+{
+ CFStringRef new_value = NULL;
+ if (cf_type != NULL)
+ {
+ CFTypeID cf_type_id = ::CFGetTypeID(cf_type);
+
+ if (cf_type_id == ::CFStringGetTypeID())
+ {
+ // Retain since we are using the existing object
+ new_value = (CFStringRef)::CFRetain(cf_type);
+ }
+ else if (cf_type_id == ::CFURLGetTypeID())
+ {
+ new_value = ::CFURLCopyFileSystemPath((CFURLRef)cf_type, kCFURLPOSIXPathStyle);
+ }
+ }
+ reset(new_value);
+ return get();
+}
+
+CFStringRef
+CFString::SetFileSystemRepresentationAndExpandTilde (const char *path)
+{
+ std::string expanded_path;
+ if (CFString::GlobPath(path, expanded_path))
+ SetFileSystemRepresentation(expanded_path.c_str());
+ else
+ reset();
+ return get();
+}
+
+const char *
+CFString::UTF8(std::string& str)
+{
+ return CFString::UTF8(get(), str);
+}
+
+// Static function that puts a copy of the UTF8 contents of CF_STR into STR
+// and returns the C string pointer that is contained in STR when successful, else
+// NULL is returned. This allows the std::string parameter to own the extracted string,
+// and also allows that string to be returned as a C string pointer that can be used.
+
+const char *
+CFString::UTF8 (CFStringRef cf_str, std::string& str)
+{
+ if (cf_str)
+ {
+ const CFStringEncoding encoding = kCFStringEncodingUTF8;
+ CFIndex max_utf8_str_len = CFStringGetLength (cf_str);
+ max_utf8_str_len = CFStringGetMaximumSizeForEncoding (max_utf8_str_len, encoding);
+ if (max_utf8_str_len > 0)
+ {
+ str.resize(max_utf8_str_len);
+ if (!str.empty())
+ {
+ if (CFStringGetCString (cf_str, &str[0], str.size(), encoding))
+ {
+ str.resize(strlen(str.c_str()));
+ return str.c_str();
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+// Static function that puts a copy of the file system representation of CF_STR
+// into STR and returns the C string pointer that is contained in STR when
+// successful, else NULL is returned. This allows the std::string parameter
+// to own the extracted string, and also allows that string to be returned as
+// a C string pointer that can be used.
+
+const char *
+CFString::FileSystemRepresentation (CFStringRef cf_str, std::string& str)
+{
+ if (cf_str)
+ {
+ CFIndex max_length = ::CFStringGetMaximumSizeOfFileSystemRepresentation (cf_str);
+ if (max_length > 0)
+ {
+ str.resize(max_length);
+ if (!str.empty())
+ {
+ if (::CFStringGetFileSystemRepresentation (cf_str, &str[0], str.size()))
+ {
+ str.erase(::strlen(str.c_str()));
+ return str.c_str();
+ }
+ }
+ }
+ }
+ str.erase();
+ return NULL;
+}
+
+
+CFIndex
+CFString::GetLength() const
+{
+ CFStringRef str = get();
+ if (str)
+ return CFStringGetLength (str);
+ return 0;
+}
+
+
+const char*
+CFString::GlobPath(const char* path, std::string &expanded_path)
+{
+ glob_t globbuf;
+ if (::glob (path, GLOB_TILDE, NULL, &globbuf) == 0)
+ {
+ expanded_path = globbuf.gl_pathv[0];
+ ::globfree (&globbuf);
+ }
+ else
+ expanded_path.clear();
+
+ return expanded_path.c_str();
+}
+
diff --git a/lldb/tools/debugserver/source/MacOSX/CFString.h b/lldb/tools/debugserver/source/MacOSX/CFString.h
new file mode 100644
index 00000000000..2b96b8237fc
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/CFString.h
@@ -0,0 +1,43 @@
+//===-- CFString.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 1/16/08.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CFString_h__
+#define __CFString_h__
+
+#include "CFUtils.h"
+#include <iosfwd>
+
+class CFString : public CFReleaser<CFStringRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFString (CFStringRef cf_str = NULL);
+ CFString (const char *s, CFStringEncoding encoding);
+ CFString (const CFString& rhs);
+ CFString& operator= (const CFString& rhs);
+ virtual ~CFString ();
+
+ const char * GetFileSystemRepresentation (std::string& str);
+ CFStringRef SetFileSystemRepresentation (const char *path);
+ CFStringRef SetFileSystemRepresentationFromCFType (CFTypeRef cf_type);
+ CFStringRef SetFileSystemRepresentationAndExpandTilde (const char *path);
+ const char * UTF8 (std::string& str);
+ CFIndex GetLength() const;
+ static const char *UTF8 (CFStringRef cf_str, std::string& str);
+ static const char *FileSystemRepresentation (CFStringRef cf_str, std::string& str);
+ static const char* GlobPath(const char* path, std::string &expanded_path);
+};
+
+#endif // #ifndef __CFString_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/CFUtils.h b/lldb/tools/debugserver/source/MacOSX/CFUtils.h
new file mode 100644
index 00000000000..afa984fa11c
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/CFUtils.h
@@ -0,0 +1,81 @@
+//===-- CFUtils.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 3/5/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CFUtils_h__
+#define __CFUtils_h__
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#ifdef __cplusplus
+
+//----------------------------------------------------------------------
+// Templatized CF helper class that can own any CF pointer and will
+// call CFRelease() on any valid pointer it owns unless that pointer is
+// explicitly released using the release() member function.
+//----------------------------------------------------------------------
+template <class T>
+class CFReleaser
+{
+public:
+ // Type names for the avlue
+ typedef T element_type;
+
+ // Constructors and destructors
+ CFReleaser(T ptr = NULL) : _ptr(ptr) { }
+ CFReleaser(const CFReleaser& copy) : _ptr(copy.get())
+ {
+ if (get())
+ ::CFRetain(get());
+ }
+ virtual ~CFReleaser() { reset(); }
+
+ // Assignments
+ CFReleaser& operator= (const CFReleaser<T>& copy)
+ {
+ if (copy != *this)
+ {
+ // Replace our owned pointer with the new one
+ reset(copy.get());
+ // Retain the current pointer that we own
+ if (get())
+ ::CFRetain(get());
+ }
+ }
+ // Get the address of the contained type
+ T * ptr_address() { return &_ptr; }
+
+ // Access the pointer itself
+ const T get() const { return _ptr; }
+ T get() { return _ptr; }
+
+ // Set a new value for the pointer and CFRelease our old
+ // value if we had a valid one.
+ void reset(T ptr = NULL)
+ {
+ if (ptr != _ptr)
+ {
+ if (_ptr != NULL)
+ ::CFRelease(_ptr);
+ _ptr = ptr;
+ }
+ }
+
+ // Release ownership without calling CFRelease
+ T release() { T tmp = _ptr; _ptr = NULL; return tmp; }
+private:
+ element_type _ptr;
+};
+
+#endif // #ifdef __cplusplus
+#endif // #ifndef __CFUtils_h__
+
diff --git a/lldb/tools/debugserver/source/MacOSX/MachDYLD.cpp b/lldb/tools/debugserver/source/MacOSX/MachDYLD.cpp
new file mode 100644
index 00000000000..76288c55bf5
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachDYLD.cpp
@@ -0,0 +1,679 @@
+//===-- MachDYLD.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/29/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachDYLD.h"
+#include "DNB.h"
+#include "DNBDataRef.h"
+#include <mach-o/loader.h>
+#include "DNBLog.h"
+
+MachDYLD::MachDYLD() :
+ m_pid(INVALID_NUB_PROCESS),
+ m_addr_size(4),
+ m_dyld_addr(INVALID_NUB_ADDRESS),
+ m_dyld_all_image_infos_addr(INVALID_NUB_ADDRESS),
+ m_dylib_info_header(),
+ m_current_dylibs(),
+ m_changed_dylibs(),
+ m_notify_break_id(INVALID_NUB_BREAK_ID),
+ m_dyld_info_mutex(PTHREAD_MUTEX_RECURSIVE)
+{
+}
+
+MachDYLD::~MachDYLD()
+{
+ Clear();
+}
+
+
+void
+MachDYLD::Clear()
+{
+ PThreadMutex::Locker locker(m_dyld_info_mutex);
+
+ nub_process_t pid = m_pid;
+ if (pid != INVALID_NUB_PROCESS)
+ {
+ DNBProcessSetSharedLibraryInfoCallback ( pid, NULL, NULL);
+ DNBBreakpointClear(pid, m_notify_break_id);
+ }
+
+ m_addr_size = 4;
+ m_dyld_addr = INVALID_NUB_ADDRESS;
+ m_dyld_all_image_infos_addr = INVALID_NUB_ADDRESS;
+ m_dylib_info_header.Clear();
+ m_current_dylibs.clear();
+ m_changed_dylibs.clear();
+ m_notify_break_id = INVALID_NUB_BREAK_ID;
+}
+
+
+void
+MachDYLD::Initialize(nub_process_t pid)
+{
+ //printf("MachDYLD::%s(0x%4.4x)\n", __FUNCTION__, pid);
+ Clear();
+ m_pid = pid;
+}
+
+
+void
+MachDYLD::ProcessStateChanged(nub_state_t state)
+{
+ //printf("MachDYLD::%s(%s)\n", __FUNCTION__, DNBStateAsString(state));
+
+ switch (state)
+ {
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateExited:
+ case eStateDetached:
+ case eStateAttaching:
+ case eStateLaunching:
+ Clear();
+ break;
+
+ case eStateStopped:
+ // Keep trying find dyld each time we stop until we do
+ if (!FoundDYLD())
+ {
+ assert(m_pid != INVALID_NUB_PROCESS);
+ DNBProcessSetSharedLibraryInfoCallback ( m_pid, CopySharedInfoCallback, this);
+ CheckForDYLDInMemory();
+ }
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ case eStateCrashed:
+ case eStateSuspended:
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+MachDYLD::SharedLibraryStateChanged(DNBExecutableImageInfo *image_infos, nub_size_t num_image_infos)
+{
+ //printf("MachDYLD::%s(%p, %u)\n", __FUNCTION__, image_infos, image_infos);
+
+}
+
+bool
+MachDYLD::FoundDYLD() const
+{
+ return m_dyld_addr != INVALID_NUB_ADDRESS;
+}
+
+bool
+MachDYLD::CheckForDYLDInMemory()
+{
+#if defined (__arm__)
+ return CheckForDYLDInMemory(0x2fe00000);
+#else
+ return CheckForDYLDInMemory(0x8fe00000);
+#endif
+}
+
+bool
+MachDYLD::CheckForDYLDInMemory(nub_addr_t addr)
+{
+ std::vector<uint8_t> dyld_header;
+ nub_size_t page_size = 0x1000;
+ dyld_header.resize(page_size);
+ nub_size_t bytes_read = DNBProcessMemoryRead(m_pid, addr, dyld_header.size(), &dyld_header[0]);
+ if (bytes_read > 0)
+ {
+ DNBDataRef::offset_t offset = 0;
+ DNBDataRef data(&dyld_header[0], bytes_read, false);
+ struct mach_header *header = (struct mach_header*)data.GetData(&offset, sizeof(struct mach_header));
+ if (header)
+ {
+ switch (header->magic)
+ {
+ case MH_MAGIC:
+ case MH_CIGAM:
+ data.SetPointerSize(4);
+ m_addr_size = 4;
+ break;
+
+ case MH_MAGIC_64:
+ case MH_CIGAM_64:
+ data.SetPointerSize(8);
+ m_addr_size = 8;
+ break;
+
+ default:
+ return false;
+ }
+
+ if (header->filetype == MH_DYLINKER)
+ {
+ // printf( "Found DYLD mach image at %8.8p", addr);
+
+ m_dyld_all_image_infos_addr = DNBProcessLookupAddress(m_pid, "dyld_all_image_infos", "/usr/lib/dyld");
+
+#if defined (__arm__)
+ m_dyld_all_image_infos_addr = 0x2fe3a004;
+#endif
+
+ if (m_dyld_all_image_infos_addr != INVALID_NUB_ADDRESS)
+ {
+ // printf( "Found DYLD data symbol 'dyld_all_image_infos' is %8.8p", m_dyld_all_image_infos_addr);
+
+ if (ReadDYLIBInfo())
+ {
+ if (m_dylib_info_header.notification != INVALID_NUB_ADDRESS)
+ {
+ m_notify_break_id = DNBBreakpointSet(m_pid, m_dylib_info_header.notification, 4, true);
+ if (NUB_BREAK_ID_IS_VALID(m_notify_break_id))
+ {
+ DNBBreakpointSetCallback(m_pid, m_notify_break_id, MachDYLD::BreakpointHit, this);
+ m_dyld_addr = addr;
+ }
+ }
+ }
+ // if (DNBLogCheckLogBit(LOG_SHLIB))
+ // Dump(DNBLogGetLogFile());
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+nub_bool_t
+MachDYLD::BreakpointHit(nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton)
+{
+ MachDYLD *dyld = (MachDYLD*) baton;
+ //printf("MachDYLD::BreakpointHit called");
+ dyld->ReadDYLIBInfo();
+ DNBProcessSharedLibrariesUpdated(pid);
+ return false; // Don't stop the process, let it continue
+}
+
+bool
+MachDYLD::ReadDYLIBInfo()
+{
+ nub_addr_t addr = m_dyld_all_image_infos_addr;
+ if (addr != INVALID_NUB_ADDRESS)
+ {
+ PThreadMutex::Locker locker(m_dyld_info_mutex);
+ //printf("MachDYLD::ReadDYLIBInfo(addr =%8.8p)", addr);
+ bool swap = false;
+ uint32_t i = 0;
+ DYLIBInfo::collection previous_dylibs;
+ previous_dylibs.swap(m_current_dylibs);
+ uint8_t all_dylib_info_data[32];
+ nub_size_t count = 8 + m_addr_size * 2;
+ nub_size_t bytes_read = DNBProcessMemoryRead(m_pid, addr, count, &all_dylib_info_data[0]);
+ if (bytes_read != count)
+ {
+ m_dylib_info_header.Clear();
+ return false;
+ }
+
+ DNBDataRef data(all_dylib_info_data, sizeof(all_dylib_info_data), swap);
+ data.SetPointerSize(m_addr_size);
+ DNBDataRef::offset_t offset = 0;
+ m_dylib_info_header.version = data.Get32(&offset);
+ m_dylib_info_header.dylib_info_count = data.Get32(&offset);
+ m_dylib_info_header.dylib_info_addr = data.GetPointer(&offset);
+ m_dylib_info_header.notification = data.GetPointer(&offset);
+ //printf( "%s: version=%d, count=%d, addr=%8.8p, notify=%8.8p",
+ // __PRETTY_FUNCTION__,
+ // m_dylib_info_header.version,
+ // m_dylib_info_header.dylib_info_count,
+ // m_dylib_info_header.dylib_info_addr,
+ // m_dylib_info_header.notification);
+
+ switch (m_dylib_info_header.version)
+ {
+ case 1: // 10.4.x and prior
+ {
+ }
+ break;
+
+ case 2: // 10.5 and later
+ {
+ }
+ break;
+
+ default:
+ //printf( "Invalid dyld all_dylib_infos version number: %d", m_dylib_info_header.version);
+ return false;
+ break;
+ }
+
+ // If we made it here, we are assuming that the all dylib info data should
+ // be valid, lets read the info array.
+ if (m_dylib_info_header.dylib_info_count > 0)
+ {
+ if (m_dylib_info_header.dylib_info_addr == 0)
+ {
+ //printf( "dyld is currently updating all_dylib_infos.");
+ }
+ else
+ {
+ m_current_dylibs.resize(m_dylib_info_header.dylib_info_count);
+ count = m_current_dylibs.size() * 3 * m_addr_size;
+ std::vector<uint8_t> info_data(count, 0);
+ bytes_read = DNBProcessMemoryRead(m_pid, m_dylib_info_header.dylib_info_addr, count, &info_data[0]);
+ if (bytes_read == count)
+ {
+ DNBDataRef::offset_t info_data_offset = 0;
+ DNBDataRef info_data_ref(&info_data[0], info_data.size(), swap);
+ info_data_ref.SetPointerSize(m_addr_size);
+ for (i = 0; info_data_ref.ValidOffset(info_data_offset); i++)
+ {
+ assert (i < m_current_dylibs.size());
+ m_current_dylibs[i].address = info_data_ref.GetPointer(&info_data_offset);
+ nub_addr_t path_addr = info_data_ref.GetPointer(&info_data_offset);
+ m_current_dylibs[i].mod_date = info_data_ref.GetPointer(&info_data_offset);
+
+ char raw_path[PATH_MAX];
+ char resolved_path[PATH_MAX];
+ bytes_read = DNBProcessMemoryRead(m_pid, path_addr, sizeof(raw_path), (char*)&raw_path[0]);
+ if (::realpath(raw_path, resolved_path))
+ m_current_dylibs[i].path = resolved_path;
+ else
+ m_current_dylibs[i].path = raw_path;
+ }
+ assert(i == m_dylib_info_header.dylib_info_count);
+
+ UpdateUUIDs();
+ }
+ else
+ {
+ //printf( "unable to read all data for all_dylib_infos.");
+ m_current_dylibs.clear();
+ return false;
+ }
+ }
+ }
+ // Read any UUID values that we can get
+ if (m_current_dylibs.empty())
+ {
+ m_changed_dylibs = previous_dylibs;
+ const size_t num_changed_dylibs = m_changed_dylibs.size();
+ for (i = 0; i < num_changed_dylibs; i++)
+ {
+ // Indicate the shared library was unloaded by giving it an invalid
+ // address...
+ m_changed_dylibs[i].address = INVALID_NUB_ADDRESS;
+ }
+ }
+ else
+ {
+ m_changed_dylibs.clear();
+
+ // Most of the time when we get shared library changes, they just
+ // get appended to the end of the list, so find out the min number
+ // of entries in the current and previous list that match and see
+ // how many are equal.
+ uint32_t curr_dylib_count = m_current_dylibs.size();
+ uint32_t prev_dylib_count = previous_dylibs.size();
+ uint32_t common_count = std::min<uint32_t>(prev_dylib_count, curr_dylib_count);
+ MachDYLD::DYLIBInfo::const_iterator curr_pos = m_current_dylibs.begin();
+ MachDYLD::DYLIBInfo::const_iterator curr_end = m_current_dylibs.end();
+ MachDYLD::DYLIBInfo::iterator prev_pos = previous_dylibs.begin();
+ uint32_t idx;
+ for (idx = 0; idx < common_count; idx++)
+ {
+ if (*curr_pos == *prev_pos)
+ {
+ ++curr_pos;
+ ++prev_pos;
+ }
+ else
+ break;
+ }
+
+ // Remove all the entries that were at the exact same index and that
+ // matched between the previous_dylibs and m_current_dylibs arrays. This will cover
+ // most of the cases as when shared libraries get loaded they get
+ // appended to the end of the list.
+ if (prev_pos != previous_dylibs.begin())
+ {
+ previous_dylibs.erase(previous_dylibs.begin(), prev_pos);
+ }
+
+ if (previous_dylibs.empty())
+ {
+ // We only have new libraries to add, they are the only ones that
+ // have changed.
+ if (curr_pos != curr_end)
+ {
+ m_changed_dylibs.assign(curr_pos, curr_end);
+ }
+ }
+ else
+ {
+ // We still have items in our previous dylib list which means either
+ // one or more shared libraries got unloaded somewhere in the middle
+ // of the list, so we will manually search for each remaining item
+ // in our current list in the previous list
+ for (; curr_pos != curr_end; ++curr_pos)
+ {
+ MachDYLD::DYLIBInfo::iterator pos = std::find(previous_dylibs.begin(), previous_dylibs.end(), *curr_pos);
+ if (pos == previous_dylibs.end())
+ {
+ // This dylib wasn't here before, add it to our change list
+ m_changed_dylibs.push_back(*curr_pos);
+ }
+ else
+ {
+ // This dylib was in our previous dylib list, it didn't
+ // change, so lets remove it from the previous list so we
+ // don't see it again.
+ previous_dylibs.erase(pos);
+ }
+ }
+
+ // The only items left if our previous_dylibs array will be shared
+ // libraries that got unloaded (still in previous list, and not
+ // mentioned in the current list).
+ if (!previous_dylibs.empty())
+ {
+ const size_t num_previous_dylibs = previous_dylibs.size();
+ for (i = 0; i < num_previous_dylibs; i++)
+ {
+ // Indicate the shared library was unloaded by giving it
+ // an invalid address...
+ previous_dylibs[i].address = INVALID_NUB_ADDRESS;
+ }
+ // Add all remaining previous_dylibs to the changed list with
+ // invalidated addresses so we know they got unloaded.
+ m_changed_dylibs.insert(m_changed_dylibs.end(), previous_dylibs.begin(), previous_dylibs.end());
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+void
+MachDYLD::UpdateUUIDs()
+{
+ bool swap = false;
+ nub_size_t page_size = 0x1000;
+ uint32_t i;
+ // Read any UUID values that we can get
+ for (i = 0; i < m_dylib_info_header.dylib_info_count; i++)
+ {
+ if (!m_current_dylibs[i].UUIDValid())
+ {
+ std::vector<uint8_t> bytes(page_size, 0);
+ nub_size_t bytes_read = DNBProcessMemoryRead(m_pid, m_current_dylibs[i].address, page_size, &bytes[0]);
+ if (bytes_read > 0)
+ {
+ DNBDataRef::offset_t offset = 0;
+ DNBDataRef data(&bytes[0], bytes_read, swap);
+ struct mach_header *header = (struct mach_header*)data.GetData(&offset, sizeof(struct mach_header));
+ if (header)
+ {
+ switch (header->magic)
+ {
+ case MH_MAGIC:
+ case MH_CIGAM:
+ data.SetPointerSize(4);
+ m_addr_size = 4;
+ break;
+
+ case MH_MAGIC_64:
+ case MH_CIGAM_64:
+ data.SetPointerSize(8);
+ m_addr_size = 8;
+ offset += 4; // Skip the extra reserved field in the 64 bit mach header
+ break;
+
+ default:
+ continue;
+ }
+
+ if (header->sizeofcmds > bytes_read)
+ {
+ bytes.resize(header->sizeofcmds);
+ nub_addr_t addr = m_current_dylibs[i].address + bytes_read;
+ bytes_read += DNBProcessMemoryRead(m_pid, addr , header->sizeofcmds - bytes_read, &bytes[bytes_read]);
+ }
+ assert(bytes_read >= header->sizeofcmds);
+ uint32_t cmd_idx;
+ DNBSegment segment;
+
+ for (cmd_idx = 0; cmd_idx < header->ncmds; cmd_idx++)
+ {
+ if (data.ValidOffsetForDataOfSize(offset, sizeof(struct load_command)))
+ {
+ struct load_command load_cmd;
+ DNBDataRef::offset_t load_cmd_offset = offset;
+ load_cmd.cmd = data.Get32(&offset);
+ load_cmd.cmdsize = data.Get32(&offset);
+ switch (load_cmd.cmd)
+ {
+ case LC_SEGMENT:
+ {
+ strncpy(segment.name, data.GetCStr(&offset, 16), 16);
+ memset(&segment.name[16], 0, DNB_MAX_SEGMENT_NAME_LENGTH - 16);
+ segment.addr = data.Get32(&offset);
+ segment.size = data.Get32(&offset);
+ m_current_dylibs[i].segments.push_back(segment);
+ }
+ break;
+
+ case LC_SEGMENT_64:
+ {
+ strncpy(segment.name, data.GetCStr(&offset, 16), 16);
+ memset(&segment.name[16], 0, DNB_MAX_SEGMENT_NAME_LENGTH - 16);
+ segment.addr = data.Get64(&offset);
+ segment.size = data.Get64(&offset);
+ m_current_dylibs[i].segments.push_back(segment);
+ }
+ break;
+
+ case LC_UUID:
+ // We found our UUID, we can stop now...
+ memcpy(m_current_dylibs[i].uuid, data.GetData(&offset, 16), 16);
+ // if (DNBLogCheckLogBit(LOG_SHLIB))
+ // {
+ // DNBLogThreaded("UUID found for aii[%d]:", i);
+ // m_current_dylibs[i].Dump(DNBLogGetLogFile());
+ // }
+ break;
+
+ default:
+ break;
+ }
+ // Set offset to be the beginning of the next load command.
+ offset = load_cmd_offset + load_cmd.cmdsize;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+nub_addr_t
+MachDYLD::GetSharedLibraryHeaderAddress(const char *shlib_path) const
+{
+ if (!m_current_dylibs.empty() && shlib_path && shlib_path[0])
+ {
+ uint32_t i;
+ for (i = 0; i<m_current_dylibs.size(); i++)
+ {
+ if (m_current_dylibs[i].path == shlib_path)
+ return m_current_dylibs[i].address;
+ }
+ }
+ return INVALID_NUB_ADDRESS;
+}
+
+
+nub_size_t
+MachDYLD::CopySharedLibraryInfo(DYLIBInfo::collection& dylib_coll, DNBExecutableImageInfo **image_infos)
+{
+ if (!dylib_coll.empty())
+ {
+ size_t i;
+ size_t total_num_segments = 0;
+ size_t segment_index = 0;
+ for (i = 0; i<dylib_coll.size(); i++)
+ {
+ total_num_segments += dylib_coll[i].segments.size();
+ }
+ size_t image_infos_byte_size = sizeof(DNBExecutableImageInfo) * dylib_coll.size();
+ size_t all_segments_byte_size = sizeof(DNBSegment) * total_num_segments;
+ size_t total_byte_size = image_infos_byte_size + all_segments_byte_size;
+
+ // Allocate enough space to fit all of the shared library information in
+ // a single buffer so consumers can free a single chunk of data when done
+ uint8_t *buf = (uint8_t*)malloc (total_byte_size);
+
+ DNBExecutableImageInfo *info = (DNBExecutableImageInfo*)buf;
+ DNBSegment *all_segments = (DNBSegment*)(buf + image_infos_byte_size);
+ if (info)
+ {
+ for (i = 0; i<dylib_coll.size(); i++)
+ {
+ strncpy(info[i].name, dylib_coll[i].path.c_str(), PATH_MAX);
+ // NULL terminate paths that are too long (redundant for path
+ // that fit, but harmless
+ info[i].name[PATH_MAX-1] = '\0';
+ info[i].header_addr = dylib_coll[i].address;
+ info[i].state = (dylib_coll[i].address == INVALID_NUB_ADDRESS ? eShlibStateUnloaded : eShlibStateLoaded);
+ memcpy(info[i].uuid, dylib_coll[i].uuid, sizeof(uuid_t));
+ info[i].num_segments = dylib_coll[i].segments.size();
+ if (info[i].num_segments == 0)
+ {
+ info[i].segments = NULL;
+ }
+ else
+ {
+ info[i].segments = &all_segments[segment_index];
+ memcpy(info[i].segments, &(dylib_coll[i].segments[0]), sizeof(DNBSegment) * info[i].num_segments);
+ segment_index += info[i].num_segments;
+ }
+
+ }
+ // Release ownership of the shared library array to the caller
+ *image_infos = info;
+ return dylib_coll.size();
+ }
+ }
+ *image_infos = NULL;
+ return 0;
+}
+
+
+
+nub_size_t
+MachDYLD::CopySharedInfoCallback(nub_process_t pid, struct DNBExecutableImageInfo **image_infos, nub_bool_t only_changed, void *baton)
+{
+ MachDYLD *dyld = (MachDYLD*) baton;
+
+ if (only_changed)
+ return dyld->CopyChangedShlibInfo(image_infos);
+ else
+ return dyld->CopyCurrentShlibInfo(image_infos);
+
+ *image_infos = NULL;
+ return 0;
+}
+
+nub_size_t
+MachDYLD::CopyCurrentShlibInfo(DNBExecutableImageInfo **image_infos)
+{
+ PThreadMutex::Locker locker(m_dyld_info_mutex);
+ return CopySharedLibraryInfo(m_current_dylibs, image_infos);
+}
+
+
+nub_size_t
+MachDYLD::CopyChangedShlibInfo(DNBExecutableImageInfo **image_infos)
+{
+ PThreadMutex::Locker locker(m_dyld_info_mutex);
+ return CopySharedLibraryInfo(m_changed_dylibs, image_infos);
+}
+
+
+
+void
+MachDYLD::DYLIBInfo::Dump(FILE *f) const
+{
+ if (f == NULL)
+ return;
+ if (address == INVALID_NUB_ADDRESS)
+ {
+ if (UUIDValid())
+ {
+ fprintf(f, "UNLOADED %8.8llx %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 %s",
+ (uint64_t)mod_date,
+ uuid[ 0], uuid[ 1], uuid[ 2], uuid[ 3],
+ uuid[ 4], uuid[ 5], uuid[ 6], uuid[ 7],
+ uuid[ 8], uuid[ 9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15],
+ path.c_str());
+ }
+ else
+ {
+ fprintf(f, "UNLOADED %8.8llx %s", (uint64_t)mod_date, path.c_str());
+ }
+ }
+ else
+ {
+ if (UUIDValid())
+ {
+ fprintf(f, "%8.8llx %8.8llx %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 %s",
+ (uint64_t)address,
+ (uint64_t)mod_date,
+ uuid[ 0], uuid[ 1], uuid[ 2], uuid[ 3],
+ uuid[ 4], uuid[ 5], uuid[ 6], uuid[ 7],
+ uuid[ 8], uuid[ 9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15],
+ path.c_str());
+ }
+ else
+ {
+ fprintf(f, "%8.8llx %8.8llx %s", (uint64_t)address, (uint64_t)mod_date, path.c_str());
+ }
+ }
+}
+
+void
+MachDYLD::Dump(FILE *f) const
+{
+ if (f == NULL)
+ return;
+
+ PThreadMutex::Locker locker(m_dyld_info_mutex);
+ fprintf(f, "\n\tMachDYLD.m_dylib_info_header: version=%d, count=%d, addr=0x%llx, notify=0x%llx",
+ m_dylib_info_header.version,
+ m_dylib_info_header.dylib_info_count,
+ (uint64_t)m_dylib_info_header.dylib_info_addr,
+ (uint64_t)m_dylib_info_header.notification);
+ uint32_t i;
+ fprintf(f, "\n\tMachDYLD.m_current_dylibs");
+ for (i = 0; i<m_current_dylibs.size(); i++)
+ m_current_dylibs[i].Dump(f);
+ fprintf(f, "\n\tMachDYLD.m_changed_dylibs");
+ for (i = 0; i<m_changed_dylibs.size(); i++)
+ m_changed_dylibs[i].Dump(f);
+}
+
diff --git a/lldb/tools/debugserver/source/MacOSX/MachDYLD.h b/lldb/tools/debugserver/source/MacOSX/MachDYLD.h
new file mode 100644
index 00000000000..1c7747cd137
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachDYLD.h
@@ -0,0 +1,145 @@
+//===-- MachDYLD.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/29/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __MachDYLD_h__
+#define __MachDYLD_h__
+
+#include "DNBDefs.h"
+#include "DNBRuntimeAction.h"
+#include "PThreadMutex.h"
+#include <map>
+#include <vector>
+#include <string>
+
+class DNBBreakpoint;
+class MachProcess;
+
+class MachDYLD : public DNBRuntimeAction
+{
+public:
+ MachDYLD ();
+ virtual ~MachDYLD ();
+
+ //------------------------------------------------------------------
+ // DNBRuntimeAction required functions
+ //------------------------------------------------------------------
+ virtual void Initialize(nub_process_t pid);
+ virtual void ProcessStateChanged(nub_state_t state);
+ virtual void SharedLibraryStateChanged(DNBExecutableImageInfo *image_infos, nub_size_t num_image_infos);
+
+protected:
+ bool CheckForDYLDInMemory();
+ bool FoundDYLD() const;
+ void Clear();
+ void Dump(FILE *f) const;
+ nub_process_t ProcessID() const { return m_pid; }
+ uint32_t AddrByteSize() const { return m_addr_size; }
+ nub_size_t CopyCurrentShlibInfo(DNBExecutableImageInfo **image_infos);
+ nub_size_t CopyChangedShlibInfo(DNBExecutableImageInfo **image_infos);
+ nub_addr_t GetSharedLibraryHeaderAddress(const char *shlib_path) const;
+ bool CheckForDYLDInMemory(nub_addr_t addr);
+ bool ReadDYLIBInfo ();
+ static nub_bool_t BreakpointHit (nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton);
+ void UpdateUUIDs();
+
+ struct DYLIBInfo
+ {
+ nub_addr_t address; // Address of mach header for this dylib
+ nub_addr_t mod_date; // Modification date for this dylib
+ std::string path; // Resolved path for this dylib
+ uint8_t uuid[16]; // UUID for this dylib if it has one, else all zeros
+ std::vector<DNBSegment> segments; // All segment vmaddr and vmsize pairs for this executable (from memory of inferior)
+
+ DYLIBInfo() :
+ address(INVALID_NUB_ADDRESS),
+ mod_date(0),
+ path(),
+ segments()
+ {
+ memset(uuid, 0, 16);
+ }
+
+ void Clear()
+ {
+ address = INVALID_NUB_ADDRESS;
+ mod_date = 0;
+ path.clear();
+ segments.clear();
+ memset(uuid, 0, 16);
+ }
+
+ bool operator == (const DYLIBInfo& rhs) const
+ {
+ return address == rhs.address
+ && mod_date == rhs.mod_date
+ && path == rhs.path
+ && memcmp(uuid, rhs.uuid, 16) == 0;
+ }
+ bool UUIDValid() const
+ {
+ return uuid[ 0] || uuid[ 1] || uuid[ 2] || uuid[ 3] ||
+ uuid[ 4] || uuid[ 5] || uuid[ 6] || uuid[ 7] ||
+ uuid[ 8] || uuid[ 9] || uuid[10] || uuid[11] ||
+ uuid[12] || uuid[13] || uuid[14] || uuid[15];
+ }
+
+ void Dump(FILE *f) const;
+ typedef std::vector<DYLIBInfo> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ };
+ struct InfoHeader
+ {
+ uint32_t version; /* == 1 in Mac OS X 10.4, == 2 in Mac OS 10.5 */
+ uint32_t dylib_info_count;
+ nub_addr_t dylib_info_addr;
+ nub_addr_t notification;
+ bool processDetachedFromSharedRegion;
+
+ InfoHeader() :
+ version(0),
+ dylib_info_count(0),
+ dylib_info_addr(INVALID_NUB_ADDRESS),
+ notification(INVALID_NUB_ADDRESS),
+ processDetachedFromSharedRegion(false)
+ {
+ }
+
+ void Clear()
+ {
+ version = 0;
+ dylib_info_count = 0;
+ dylib_info_addr = INVALID_NUB_ADDRESS;
+ notification = INVALID_NUB_ADDRESS;
+ processDetachedFromSharedRegion = false;
+ }
+
+ bool IsValid() const
+ {
+ return version == 1 || version == 2;
+ }
+ };
+ static nub_size_t CopySharedLibraryInfo(DYLIBInfo::collection& dylib_coll, DNBExecutableImageInfo **image_infos);
+ static nub_size_t CopySharedInfoCallback(nub_process_t pid, struct DNBExecutableImageInfo **image_infos, nub_bool_t only_changed, void *baton);
+ nub_process_t m_pid;
+ uint32_t m_addr_size;
+ nub_addr_t m_dyld_addr;
+ nub_addr_t m_dyld_all_image_infos_addr;
+ InfoHeader m_dylib_info_header;
+ DYLIBInfo::collection m_current_dylibs; // Current shared libraries information
+ DYLIBInfo::collection m_changed_dylibs; // Shared libraries that changed since last shared library update
+ nub_break_t m_notify_break_id;
+ mutable PThreadMutex m_dyld_info_mutex;
+};
+
+#endif // #ifndef __MachDYLD_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/MachException.cpp b/lldb/tools/debugserver/source/MacOSX/MachException.cpp
new file mode 100644
index 00000000000..356160bb621
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachException.cpp
@@ -0,0 +1,533 @@
+//===-- MachException.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/18/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachException.h"
+#include "MachProcess.h"
+#include "DNB.h"
+#include "DNBError.h"
+#include <sys/types.h>
+#include "DNBLog.h"
+#include "PThreadMutex.h"
+#include "SysSignal.h"
+#include <errno.h>
+#include <sys/ptrace.h>
+
+// Routine mach_exception_raise
+extern "C"
+kern_return_t catch_mach_exception_raise
+(
+ mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ mach_exception_data_t code,
+ mach_msg_type_number_t codeCnt
+);
+
+extern "C"
+kern_return_t catch_mach_exception_raise_state
+(
+ mach_port_t exception_port,
+ exception_type_t exception,
+ const mach_exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ int *flavor,
+ const thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt
+);
+
+// Routine mach_exception_raise_state_identity
+extern "C"
+kern_return_t catch_mach_exception_raise_state_identity
+(
+ mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ mach_exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ int *flavor,
+ thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt
+);
+
+extern "C" boolean_t mach_exc_server(
+ mach_msg_header_t *InHeadP,
+ mach_msg_header_t *OutHeadP);
+
+// Any access to the g_message variable should be done by locking the
+// g_message_mutex first, using the g_message variable, then unlocking
+// the g_message_mutex. See MachException::Message::CatchExceptionRaise()
+// for sample code.
+
+static MachException::Data *g_message = NULL;
+//static pthread_mutex_t g_message_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+extern "C"
+kern_return_t
+catch_mach_exception_raise_state
+(
+ mach_port_t exc_port,
+ exception_type_t exc_type,
+ const mach_exception_data_t exc_data,
+ mach_msg_type_number_t exc_data_count,
+ int * flavor,
+ const thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t * new_stateCnt
+)
+{
+ if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
+ {
+ DNBLogThreaded("::%s ( exc_port = 0x%4.4x, exc_type = %d ( %s ), exc_data = " MACH_EXCEPTION_DATA_FMT_HEX ", exc_data_count = %d)",
+ __FUNCTION__,
+ exc_port,
+ exc_type, MachException::Name(exc_type),
+ exc_data,
+ exc_data_count);
+ }
+ return KERN_FAILURE;
+}
+
+extern "C"
+kern_return_t
+catch_mach_exception_raise_state_identity
+(
+ mach_port_t exc_port,
+ mach_port_t thread_port,
+ mach_port_t task_port,
+ exception_type_t exc_type,
+ mach_exception_data_t exc_data,
+ mach_msg_type_number_t exc_data_count,
+ int * flavor,
+ thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt
+)
+{
+ kern_return_t kret;
+ if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
+ {
+ DNBLogThreaded("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = 0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { " MACH_EXCEPTION_DATA_FMT_HEX ", " MACH_EXCEPTION_DATA_FMT_HEX " })",
+ __FUNCTION__,
+ exc_port,
+ thread_port,
+ task_port,
+ exc_type, MachException::Name(exc_type),
+ exc_data_count,
+ exc_data_count > 0 ? exc_data[0] : 0xBADDBADD,
+ exc_data_count > 1 ? exc_data[1] : 0xBADDBADD);
+ }
+ kret = mach_port_deallocate (mach_task_self (), task_port);
+ kret = mach_port_deallocate (mach_task_self (), thread_port);
+
+ return KERN_FAILURE;
+}
+
+extern "C"
+kern_return_t
+catch_mach_exception_raise
+(
+ mach_port_t exc_port,
+ mach_port_t thread_port,
+ mach_port_t task_port,
+ exception_type_t exc_type,
+ mach_exception_data_t exc_data,
+ mach_msg_type_number_t exc_data_count)
+{
+ if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
+ {
+ DNBLogThreaded("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = 0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { " MACH_EXCEPTION_DATA_FMT_HEX ", " MACH_EXCEPTION_DATA_FMT_HEX " })",
+ __FUNCTION__,
+ exc_port,
+ thread_port,
+ task_port,
+ exc_type, MachException::Name(exc_type),
+ exc_data_count,
+ exc_data_count > 0 ? exc_data[0] : 0xBADDBADD,
+ exc_data_count > 1 ? exc_data[1] : 0xBADDBADD);
+ }
+
+ g_message->task_port = task_port;
+ g_message->thread_port = thread_port;
+ g_message->exc_type = exc_type;
+ g_message->exc_data.resize(exc_data_count);
+ ::memcpy (&g_message->exc_data[0], exc_data, g_message->exc_data.size() * sizeof (mach_exception_data_type_t));
+ return KERN_SUCCESS;
+}
+
+
+void
+MachException::Message::Dump() const
+{
+ DNBLogThreadedIf(LOG_EXCEPTIONS,
+ " exc_msg { bits = 0x%8.8lx size = 0x%8.8lx remote-port = 0x%8.8lx local-port = 0x%8.8lx reserved = 0x%8.8lx id = 0x%8.8lx } ",
+ exc_msg.hdr.msgh_bits,
+ exc_msg.hdr.msgh_size,
+ exc_msg.hdr.msgh_remote_port,
+ exc_msg.hdr.msgh_local_port,
+ exc_msg.hdr.msgh_reserved,
+ exc_msg.hdr.msgh_id);
+
+ DNBLogThreadedIf(LOG_EXCEPTIONS,
+ "reply_msg { bits = 0x%8.8lx size = 0x%8.8lx remote-port = 0x%8.8lx local-port = 0x%8.8lx reserved = 0x%8.8lx id = 0x%8.8lx }",
+ reply_msg.hdr.msgh_bits,
+ reply_msg.hdr.msgh_size,
+ reply_msg.hdr.msgh_remote_port,
+ reply_msg.hdr.msgh_local_port,
+ reply_msg.hdr.msgh_reserved,
+ reply_msg.hdr.msgh_id);
+
+ state.Dump();
+}
+
+bool
+MachException::Data::GetStopInfo(struct DNBThreadStopInfo *stop_info) const
+{
+ // Zero out the structure.
+ memset(stop_info, 0, sizeof(struct DNBThreadStopInfo));
+ // We always stop with a mach exceptions
+ stop_info->reason = eStopTypeException;
+ // Save the EXC_XXXX exception type
+ stop_info->details.exception.type = exc_type;
+
+ // Fill in a text description
+ const char * exc_name = MachException::Name(exc_type);
+ char *desc = stop_info->description;
+ const char *end_desc = desc + DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH;
+ if (exc_name)
+ desc += snprintf(desc, DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH, "%s", exc_name);
+ else
+ desc += snprintf(desc, DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH, "%i", exc_type);
+
+ stop_info->details.exception.data_count = exc_data.size();
+
+ int soft_signal = SoftSignal();
+ if (soft_signal)
+ {
+ if (desc < end_desc)
+ {
+ const char *sig_str = SysSignal::Name(soft_signal);
+ desc += snprintf(desc, end_desc - desc, " EXC_SOFT_SIGNAL( %i ( %s ))", soft_signal, sig_str ? sig_str : "unknown signal");
+ }
+ }
+ else
+ {
+ // No special disassembly for exception data, just
+ size_t idx;
+ if (desc < end_desc)
+ {
+ desc += snprintf(desc, end_desc - desc, " data[%zu] = {", stop_info->details.exception.data_count);
+
+ for (idx = 0; desc < end_desc && idx < stop_info->details.exception.data_count; ++idx)
+ desc += snprintf(desc, end_desc - desc, MACH_EXCEPTION_DATA_FMT_MINHEX "%c", exc_data[idx], ((idx + 1 == stop_info->details.exception.data_count) ? '}' : ','));
+ }
+ }
+
+ // Copy the exception data
+ size_t i;
+ for (i=0; i<stop_info->details.exception.data_count; i++)
+ stop_info->details.exception.data[i] = exc_data[i];
+
+ return true;
+}
+
+
+void
+MachException::Data::DumpStopReason() const
+{
+ int soft_signal = SoftSignal();
+ if (soft_signal)
+ {
+ const char *signal_str = SysSignal::Name(soft_signal);
+ if (signal_str)
+ DNBLog("signal(%s)", signal_str);
+ else
+ DNBLog("signal(%i)", soft_signal);
+ return;
+ }
+ DNBLog("%s", Name(exc_type));
+}
+
+kern_return_t
+MachException::Message::Receive(mach_port_t port, mach_msg_option_t options, mach_msg_timeout_t timeout, mach_port_t notify_port)
+{
+ DNBError err;
+ const bool log_exceptions = DNBLogCheckLogBit(LOG_EXCEPTIONS);
+ mach_msg_timeout_t mach_msg_timeout = options & MACH_RCV_TIMEOUT ? timeout : 0;
+ if (log_exceptions && ((options & MACH_RCV_TIMEOUT) == 0))
+ {
+ // Dump this log message if we have no timeout in case it never returns
+ DNBLogThreaded("::mach_msg ( msg->{bits = %#x, size = %u remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x)",
+ exc_msg.hdr.msgh_bits,
+ exc_msg.hdr.msgh_size,
+ exc_msg.hdr.msgh_remote_port,
+ exc_msg.hdr.msgh_local_port,
+ exc_msg.hdr.msgh_reserved,
+ exc_msg.hdr.msgh_id,
+ options,
+ 0,
+ sizeof (exc_msg.data),
+ port,
+ mach_msg_timeout,
+ notify_port);
+ }
+
+ err = ::mach_msg (&exc_msg.hdr,
+ options, // options
+ 0, // Send size
+ sizeof (exc_msg.data), // Receive size
+ port, // exception port to watch for exception on
+ mach_msg_timeout, // timeout in msec (obeyed only if MACH_RCV_TIMEOUT is ORed into the options parameter)
+ notify_port);
+
+ // Dump any errors we get
+ if (log_exceptions)
+ {
+ err.LogThreaded("::mach_msg ( msg->{bits = %#x, size = %u remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x)",
+ exc_msg.hdr.msgh_bits,
+ exc_msg.hdr.msgh_size,
+ exc_msg.hdr.msgh_remote_port,
+ exc_msg.hdr.msgh_local_port,
+ exc_msg.hdr.msgh_reserved,
+ exc_msg.hdr.msgh_id,
+ options,
+ 0,
+ sizeof (exc_msg.data),
+ port,
+ mach_msg_timeout,
+ notify_port);
+ }
+ return err.Error();
+}
+
+bool
+MachException::Message::CatchExceptionRaise()
+{
+ bool success = false;
+ // locker will keep a mutex locked until it goes out of scope
+// PThreadMutex::Locker locker(&g_message_mutex);
+ // DNBLogThreaded("calling mach_exc_server");
+ g_message = &state;
+ // The exc_server function is the MIG generated server handling function
+ // to handle messages from the kernel relating to the occurrence of an
+ // exception in a thread. Such messages are delivered to the exception port
+ // set via thread_set_exception_ports or task_set_exception_ports. When an
+ // exception occurs in a thread, the thread sends an exception message to
+ // its exception port, blocking in the kernel waiting for the receipt of a
+ // reply. The exc_server function performs all necessary argument handling
+ // for this kernel message and calls catch_exception_raise,
+ // catch_exception_raise_state or catch_exception_raise_state_identity,
+ // which should handle the exception. If the called routine returns
+ // KERN_SUCCESS, a reply message will be sent, allowing the thread to
+ // continue from the point of the exception; otherwise, no reply message
+ // is sent and the called routine must have dealt with the exception
+ // thread directly.
+ if (mach_exc_server (&exc_msg.hdr, &reply_msg.hdr))
+ {
+ success = true;
+ }
+ else if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
+ {
+ DNBLogThreaded("mach_exc_server returned zero...");
+ }
+ g_message = NULL;
+ return success;
+}
+
+
+
+kern_return_t
+MachException::Message::Reply(MachProcess *process, int signal)
+{
+ // Reply to the exception...
+ DNBError err;
+
+ // If we had a soft signal, we need to update the thread first so it can
+ // continue without signaling
+ int soft_signal = state.SoftSignal();
+ if (soft_signal)
+ {
+ int state_pid = -1;
+ if (process->Task().TaskPort() == state.task_port)
+ {
+ // This is our task, so we can update the signal to send to it
+ state_pid = process->ProcessID();
+ soft_signal = signal;
+ }
+ else
+ {
+ err = ::pid_for_task(state.task_port, &state_pid);
+ }
+
+ assert (state_pid != -1);
+ if (state_pid != -1)
+ {
+ errno = 0;
+ if (::ptrace (PT_THUPDATE, state_pid, (caddr_t)state.thread_port, soft_signal) != 0)
+ err.SetError(errno, DNBError::POSIX);
+ else
+ err.Clear();
+
+ if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail())
+ err.LogThreaded("::ptrace (request = PT_THUPDATE, pid = 0x%4.4x, tid = 0x%4.4x, signal = %i)", state_pid, state.thread_port, soft_signal);
+ }
+ }
+
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "::mach_msg ( msg->{bits = %#x, size = %u, remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x)",
+ reply_msg.hdr.msgh_bits,
+ reply_msg.hdr.msgh_size,
+ reply_msg.hdr.msgh_remote_port,
+ reply_msg.hdr.msgh_local_port,
+ reply_msg.hdr.msgh_reserved,
+ reply_msg.hdr.msgh_id,
+ MACH_SEND_MSG | MACH_SEND_INTERRUPT,
+ reply_msg.hdr.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ err = ::mach_msg ( &reply_msg.hdr,
+ MACH_SEND_MSG | MACH_SEND_INTERRUPT,
+ reply_msg.hdr.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ if (err.Fail())
+ {
+ if (err.Error() == MACH_SEND_INTERRUPTED)
+ {
+ if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
+ err.LogThreaded("::mach_msg() - send interrupted");
+ // TODO: keep retrying to reply???
+ }
+ else
+ {
+ if (state.task_port == process->Task().TaskPort())
+ {
+ if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
+ err.LogThreaded("::mach_msg() - failed (task)");
+ abort ();
+ }
+ else
+ {
+ if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
+ err.LogThreaded("::mach_msg() - failed (child of task)");
+ }
+ }
+ }
+
+ return err.Error();
+}
+
+
+void
+MachException::Data::Dump() const
+{
+ const char *exc_type_name = MachException::Name(exc_type);
+ DNBLogThreadedIf(LOG_EXCEPTIONS, " state { task_port = 0x%4.4x, thread_port = 0x%4.4x, exc_type = %i (%s) ...", task_port, thread_port, exc_type, exc_type_name ? exc_type_name : "???");
+
+ const size_t exc_data_count = exc_data.size();
+ // Dump any special exception data contents
+ int soft_signal = SoftSignal();
+ if (soft_signal != 0)
+ {
+ const char *sig_str = SysSignal::Name(soft_signal);
+ DNBLogThreadedIf(LOG_EXCEPTIONS, " exc_data: EXC_SOFT_SIGNAL (%i (%s))", soft_signal, sig_str ? sig_str : "unknown signal");
+ }
+ else
+ {
+ // No special disassembly for this data, just dump the data
+ size_t idx;
+ for (idx = 0; idx < exc_data_count; ++idx)
+ {
+ DNBLogThreadedIf(LOG_EXCEPTIONS, " exc_data[%u]: " MACH_EXCEPTION_DATA_FMT_HEX, idx, exc_data[idx]);
+ }
+ }
+}
+
+
+kern_return_t
+MachException::PortInfo::Save (task_t task)
+{
+ count = (sizeof (ports) / sizeof (ports[0]));
+ DNBLogThreadedIf(LOG_EXCEPTIONS | LOG_VERBOSE, "MachException::PortInfo::Save ( task = 0x%4.4x )", task);
+ DNBError err;
+ err = ::task_get_exception_ports (task, EXC_MASK_ALL, masks, &count, ports, behaviors, flavors);
+ if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail())
+ err.LogThreaded("::task_get_exception_ports ( task = 0x%4.4x, mask = 0x%x, maskCnt => %u, ports, behaviors, flavors )", task, EXC_MASK_ALL, count);
+ if (err.Fail())
+ count = 0;
+ return err.Error();
+}
+
+kern_return_t
+MachException::PortInfo::Restore (task_t task)
+{
+ DNBLogThreadedIf(LOG_EXCEPTIONS | LOG_VERBOSE, "MachException::PortInfo::Restore( task = 0x%4.4x )", task);
+ uint32_t i = 0;
+ DNBError err;
+ if (count > 0)
+ {
+ for (i = 0; i < count; i++)
+ {
+ err = ::task_set_exception_ports (task, masks[i], ports[i], behaviors[i], flavors[i]);
+ if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail())
+ {
+ err.LogThreaded("::task_set_exception_ports ( task = 0x%4.4x, exception_mask = 0x%8.8x, new_port = 0x%4.4x, behavior = 0x%8.8x, new_flavor = 0x%8.8x )", task, masks[i], ports[i], behaviors[i], flavors[i]);
+ // Bail if we encounter any errors
+ }
+
+ if (err.Fail())
+ break;
+ }
+ }
+ count = 0;
+ return err.Error();
+}
+
+const char *
+MachException::Name(exception_type_t exc_type)
+{
+ switch (exc_type)
+ {
+ case EXC_BAD_ACCESS: return "EXC_BAD_ACCESS";
+ case EXC_BAD_INSTRUCTION: return "EXC_BAD_INSTRUCTION";
+ case EXC_ARITHMETIC: return "EXC_ARITHMETIC";
+ case EXC_EMULATION: return "EXC_EMULATION";
+ case EXC_SOFTWARE: return "EXC_SOFTWARE";
+ case EXC_BREAKPOINT: return "EXC_BREAKPOINT";
+ case EXC_SYSCALL: return "EXC_SYSCALL";
+ case EXC_MACH_SYSCALL: return "EXC_MACH_SYSCALL";
+ case EXC_RPC_ALERT: return "EXC_RPC_ALERT";
+#ifdef EXC_CRASH
+ case EXC_CRASH: return "EXC_CRASH";
+#endif
+ default:
+ break;
+ }
+ return NULL;
+}
+
+
+
diff --git a/lldb/tools/debugserver/source/MacOSX/MachException.h b/lldb/tools/debugserver/source/MacOSX/MachException.h
new file mode 100644
index 00000000000..5dc394bd55a
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachException.h
@@ -0,0 +1,147 @@
+//===-- MachException.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/18/07.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef __MachException_h__
+#define __MachException_h__
+
+#include <mach/mach.h>
+#include <vector>
+#include "DNBConfig.h"
+
+#ifdef HAVE_64_BIT_MACH_EXCEPTIONS
+
+#define MACH_EXCEPTION_DATA_FMT_DEC "%lld"
+#define MACH_EXCEPTION_DATA_FMT_HEX "0x%16.16llx"
+#define MACH_EXCEPTION_DATA_FMT_MINHEX "0x%llx"
+
+#else
+
+#define MACH_EXCEPTION_DATA_FMT_DEC "%d"
+#define MACH_EXCEPTION_DATA_FMT_HEX "0x%8.8x"
+#define MACH_EXCEPTION_DATA_FMT_MINHEX "0x%x"
+
+#endif
+
+class MachProcess;
+class PThreadMutex;
+
+typedef union MachMessageTag
+{
+ mach_msg_header_t hdr;
+ char data[1024];
+} MachMessage;
+
+
+class MachException
+{
+public:
+
+ struct PortInfo
+ {
+ exception_mask_t masks[EXC_TYPES_COUNT];
+ mach_port_t ports[EXC_TYPES_COUNT];
+ exception_behavior_t behaviors[EXC_TYPES_COUNT];
+ thread_state_flavor_t flavors[EXC_TYPES_COUNT];
+ mach_msg_type_number_t count;
+
+ kern_return_t Save(task_t task);
+ kern_return_t Restore(task_t task);
+ };
+
+ struct Data
+ {
+ task_t task_port;
+ thread_t thread_port;
+ exception_type_t exc_type;
+ std::vector<mach_exception_data_type_t> exc_data;
+ Data() :
+ task_port(TASK_NULL),
+ thread_port(THREAD_NULL),
+ exc_type(0),
+ exc_data()
+ {
+ }
+
+ void Clear()
+ {
+ task_port = TASK_NULL;
+ thread_port = THREAD_NULL;
+ exc_type = 0;
+ exc_data.clear();
+ }
+ bool IsValid() const
+ {
+ return task_port != TASK_NULL &&
+ thread_port != THREAD_NULL &&
+ exc_type != 0;
+ }
+ // Return the SoftSignal for this MachException data, or zero if there is none
+ int SoftSignal() const
+ {
+ if (exc_type == EXC_SOFTWARE && exc_data.size() == 2 && exc_data[0] == EXC_SOFT_SIGNAL)
+ return exc_data[1];
+ return 0;
+ }
+ bool IsBreakpoint() const
+ {
+ return (exc_type == EXC_BREAKPOINT) || ((exc_type == EXC_SOFTWARE) && exc_data[0] == 1);
+ }
+ void Dump() const;
+ void DumpStopReason() const;
+ bool GetStopInfo(struct DNBThreadStopInfo *stop_info) const;
+ };
+
+ struct Message
+ {
+ MachMessage exc_msg;
+ MachMessage reply_msg;
+ Data state;
+
+ Message() :
+ state()
+ {
+ memset(&exc_msg, 0, sizeof(exc_msg));
+ memset(&reply_msg, 0, sizeof(reply_msg));
+ }
+ bool CatchExceptionRaise();
+ void Dump() const;
+ kern_return_t Reply (MachProcess *process, int signal);
+ kern_return_t Receive( mach_port_t receive_port,
+ mach_msg_option_t options,
+ mach_msg_timeout_t timeout,
+ mach_port_t notify_port = MACH_PORT_NULL);
+
+ typedef std::vector<Message> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ };
+
+ enum
+ {
+ e_actionForward, // Forward signal to inferior process
+ e_actionStop, // Stop when this signal is received
+ };
+ struct Action
+ {
+ task_t task_port; // Set to TASK_NULL for any TASK
+ thread_t thread_port; // Set to THREAD_NULL for any thread
+ exception_type_t exc_mask; // Mach exception mask to watch for
+ std::vector<mach_exception_data_type_t> exc_data_mask; // Mask to apply to exception data, or empty to ignore exc_data value for exception
+ std::vector<mach_exception_data_type_t> exc_data_value; // Value to compare to exception data after masking, or empty to ignore exc_data value for exception
+ uint8_t flags; // Action flags describing what to do with the exception
+ };
+ static const char *Name(exception_type_t exc_type);
+};
+
+#endif
diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp b/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp
new file mode 100644
index 00000000000..2bfc7603e2a
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp
@@ -0,0 +1,2008 @@
+//===-- MachProcess.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/15/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DNB.h"
+#include <mach/mach.h>
+#include <spawn.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "MacOSX/CFUtils.h"
+#include "SysSignal.h"
+
+#include <algorithm>
+#include <map>
+
+#include "DNBDataRef.h"
+#include "DNBLog.h"
+#include "DNBThreadResumeActions.h"
+#include "DNBTimer.h"
+#include "MachProcess.h"
+#include "PseudoTerminal.h"
+
+#include "CFBundle.h"
+#include "CFData.h"
+#include "CFString.h"
+
+static CFStringRef CopyBundleIDForPath (const char *app_buncle_path, DNBError &err_str);
+
+#if defined (__arm__)
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <SpringBoardServices/SpringBoardServer.h>
+#include <SpringBoardServices/SBSWatchdogAssertion.h>
+
+
+static bool
+IsSBProcess (nub_process_t pid)
+{
+ bool opt_runningApps = true;
+ bool opt_debuggable = false;
+
+ CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable));
+ if (sbsAppIDs.get() != NULL)
+ {
+ CFIndex count = ::CFArrayGetCount (sbsAppIDs.get());
+ CFIndex i = 0;
+ for (i = 0; i < count; i++)
+ {
+ CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i);
+
+ // Get the process id for the app (if there is one)
+ pid_t sbs_pid = INVALID_NUB_PROCESS;
+ if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &sbs_pid) == TRUE)
+ {
+ if (sbs_pid == pid)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+#endif
+
+#if 0
+#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_LOG(fmt, ...)
+#endif
+
+#ifndef MACH_PROCESS_USE_POSIX_SPAWN
+#define MACH_PROCESS_USE_POSIX_SPAWN 1
+#endif
+
+
+MachProcess::MachProcess() :
+ m_pid (0),
+ m_child_stdin (-1),
+ m_child_stdout (-1),
+ m_child_stderr (-1),
+ m_path (),
+ m_args (),
+ m_task (this),
+ m_flags (eMachProcessFlagsNone),
+ m_stdio_thread (0),
+ m_stdio_mutex (PTHREAD_MUTEX_RECURSIVE),
+ m_stdout_data (),
+ m_threadList (),
+ m_exception_messages (),
+ m_exception_messages_mutex (PTHREAD_MUTEX_RECURSIVE),
+ m_err (KERN_SUCCESS),
+ m_state (eStateUnloaded),
+ m_state_mutex (PTHREAD_MUTEX_RECURSIVE),
+ m_events (0, kAllEventsMask),
+ m_breakpoints (),
+ m_watchpoints (),
+ m_name_to_addr_callback(NULL),
+ m_name_to_addr_baton(NULL),
+ m_image_infos_callback(NULL),
+ m_image_infos_baton(NULL)
+{
+ DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__);
+}
+
+MachProcess::~MachProcess()
+{
+ DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__);
+ Clear();
+}
+
+pid_t
+MachProcess::SetProcessID(pid_t pid)
+{
+ // Free any previous process specific data or resources
+ Clear();
+ // Set the current PID appropriately
+ if (pid == 0)
+ m_pid == ::getpid ();
+ else
+ m_pid = pid;
+ return m_pid; // Return actualy PID in case a zero pid was passed in
+}
+
+nub_state_t
+MachProcess::GetState()
+{
+ // If any other threads access this we will need a mutex for it
+ PTHREAD_MUTEX_LOCKER(locker, m_state_mutex);
+ return m_state;
+}
+
+const char *
+MachProcess::ThreadGetName(nub_thread_t tid)
+{
+ return m_threadList.GetName(tid);
+}
+
+nub_state_t
+MachProcess::ThreadGetState(nub_thread_t tid)
+{
+ return m_threadList.GetState(tid);
+}
+
+
+nub_size_t
+MachProcess::GetNumThreads () const
+{
+ return m_threadList.NumThreads();
+}
+
+nub_thread_t
+MachProcess::GetThreadAtIndex (nub_size_t thread_idx) const
+{
+ return m_threadList.ThreadIDAtIndex(thread_idx);
+}
+
+uint32_t
+MachProcess::GetThreadIndexFromThreadID (nub_thread_t tid)
+{
+ return m_threadList.GetThreadIndexByID(tid);
+}
+
+nub_thread_t
+MachProcess::GetCurrentThread ()
+{
+ return m_threadList.CurrentThreadID();
+}
+
+nub_thread_t
+MachProcess::SetCurrentThread(nub_thread_t tid)
+{
+ return m_threadList.SetCurrentThread(tid);
+}
+
+bool
+MachProcess::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const
+{
+ return m_threadList.GetThreadStoppedReason(tid, stop_info);
+}
+
+void
+MachProcess::DumpThreadStoppedReason(nub_thread_t tid) const
+{
+ return m_threadList.DumpThreadStoppedReason(tid);
+}
+
+const char *
+MachProcess::GetThreadInfo(nub_thread_t tid) const
+{
+ return m_threadList.GetThreadInfo(tid);
+}
+
+const DNBRegisterSetInfo *
+MachProcess::GetRegisterSetInfo(nub_thread_t tid, nub_size_t *num_reg_sets ) const
+{
+ return DNBArch::GetRegisterSetInfo (num_reg_sets);
+}
+
+bool
+MachProcess::GetRegisterValue ( nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value ) const
+{
+ return m_threadList.GetRegisterValue(tid, set, reg, value);
+}
+
+bool
+MachProcess::SetRegisterValue ( nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value ) const
+{
+ return m_threadList.SetRegisterValue(tid, set, reg, value);
+}
+
+void
+MachProcess::SetState(nub_state_t new_state)
+{
+ // If any other threads access this we will need a mutex for it
+ uint32_t event_mask = 0;
+
+ // Scope for mutex locker
+ {
+ PTHREAD_MUTEX_LOCKER(locker, m_state_mutex);
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::SetState ( %s )", DNBStateAsString(new_state));
+
+ const nub_state_t old_state = m_state;
+
+ if (old_state != new_state)
+ {
+ if (NUB_STATE_IS_STOPPED(new_state))
+ event_mask = eEventProcessStoppedStateChanged;
+ else
+ event_mask = eEventProcessRunningStateChanged;
+
+ m_state = new_state;
+ if (new_state == eStateStopped)
+ m_stop_count++;
+ }
+ }
+
+ if (event_mask != 0)
+ {
+ m_events.SetEvents (event_mask);
+
+ // Wait for the event bit to reset if a reset ACK is requested
+ m_events.WaitForResetAck(event_mask);
+ }
+
+}
+
+void
+MachProcess::Clear()
+{
+ // Clear any cached thread list while the pid and task are still valid
+
+ m_task.Clear();
+ // Now clear out all member variables
+ m_pid = INVALID_NUB_PROCESS;
+ CloseChildFileDescriptors();
+ m_path.clear();
+ m_args.clear();
+ SetState(eStateUnloaded);
+ m_flags = eMachProcessFlagsNone;
+ m_stop_count = 0;
+ m_threadList.Clear();
+ {
+ PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex);
+ m_exception_messages.clear();
+ }
+ m_err.Clear();
+
+}
+
+
+bool
+MachProcess::StartSTDIOThread()
+{
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( )", __FUNCTION__);
+ // Create the thread that watches for the child STDIO
+ m_err = ::pthread_create (&m_stdio_thread, NULL, MachProcess::STDIOThread, this);
+ return m_err.Success();
+}
+
+
+nub_addr_t
+MachProcess::LookupSymbol(const char *name, const char *shlib)
+{
+ if (m_name_to_addr_callback != NULL && name && name[0])
+ return m_name_to_addr_callback(ProcessID(), name, shlib, m_name_to_addr_baton);
+ return INVALID_NUB_ADDRESS;
+}
+
+bool
+MachProcess::Resume (const DNBThreadResumeActions& thread_actions)
+{
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Resume ()");
+ nub_state_t state = GetState();
+
+ if (CanResume(state))
+ {
+ PrivateResume(thread_actions);
+ }
+ else if (state == eStateRunning)
+ {
+ DNBLogThreadedIf(LOG_PROCESS, "Resume() - task 0x%x is running, ignoring...", m_task.TaskPort());
+ m_err.Clear();
+
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_PROCESS, "Resume() - task 0x%x can't continue, ignoring...", m_task.TaskPort());
+ m_err.SetError(UINT_MAX, DNBError::Generic);
+ }
+ return m_err.Success();
+}
+
+bool
+MachProcess::Kill (const struct timespec *timeout_abstime)
+{
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill ()");
+ nub_state_t state = DoSIGSTOP(true);
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() state = %s", DNBStateAsString(state));
+ errno = 0;
+ ::ptrace (PT_KILL, m_pid, 0, 0);
+ m_err.SetErrorToErrno();
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() ::ptrace (PT_KILL, pid=%u, 0, 0) => 0x%8.8x (%s)", m_err.Error(), m_err.AsString());
+ PrivateResume (DNBThreadResumeActions (eStateRunning, 0));
+ return true;
+}
+
+bool
+MachProcess::Signal (int signal, const struct timespec *timeout_abstime)
+{
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p)", signal, timeout_abstime);
+ nub_state_t state = GetState();
+ if (::kill (ProcessID(), signal) == 0)
+ {
+ m_err.Clear();
+ // If we were running and we have a timeout, wait for the signal to stop
+ if (IsRunning(state) && timeout_abstime)
+ {
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p) waiting for signal to stop process...", signal, timeout_abstime);
+ m_events.WaitForSetEvents(eEventProcessStoppedStateChanged, timeout_abstime);
+ state = GetState();
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p) state = %s", signal, timeout_abstime, DNBStateAsString(state));
+ return !IsRunning (state);
+ }
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p) not waiting...", signal, timeout_abstime);
+ }
+ else
+ {
+ m_err.SetError(errno, DNBError::POSIX);
+ m_err.LogThreadedIfError("kill (pid = %d, signo = %i)", ProcessID(), signal);
+ }
+ return m_err.Success();
+
+}
+
+nub_state_t
+MachProcess::DoSIGSTOP (bool clear_bps_and_wps)
+{
+ nub_state_t state = GetState();
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s", DNBStateAsString (state));
+
+ if (!IsRunning(state))
+ {
+ if (clear_bps_and_wps)
+ {
+ DisableAllBreakpoints (true);
+ DisableAllWatchpoints (true);
+ clear_bps_and_wps = false;
+ }
+
+ // Resume our process
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s -- resuming process", DNBStateAsString (state));
+ PrivateResume (DNBThreadResumeActions (eStateRunning, 0));
+
+ // Reset the event that says we were indeed running
+ m_events.ResetEvents(eEventProcessRunningStateChanged);
+ state = GetState();
+ }
+
+ // We need to be stopped in order to be able to detach, so we need
+ // to send ourselves a SIGSTOP
+
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s -- sending SIGSTOP", DNBStateAsString (state));
+ struct timespec sigstop_timeout;
+ DNBTimer::OffsetTimeOfDay(&sigstop_timeout, 2, 0);
+ Signal (SIGSTOP, &sigstop_timeout);
+ if (clear_bps_and_wps)
+ {
+ DisableAllBreakpoints (true);
+ DisableAllWatchpoints (true);
+ clear_bps_and_wps = false;
+ }
+ return GetState();
+}
+
+bool
+MachProcess::Detach()
+{
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach()");
+
+ nub_state_t state = DoSIGSTOP(true);
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach() DoSIGSTOP() returned %s", DNBStateAsString(state));
+
+
+ // Don't reply to our SIGSTOP exception, just make sure no threads
+ // are still suspended.
+ PrivateResume (DNBThreadResumeActions (eStateRunning, 0));
+
+
+ // Detach from our process
+ errno = 0;
+ nub_process_t pid = m_pid;
+ ::ptrace (PT_DETACH, pid, (caddr_t)1, 0);
+ m_err.SetError (errno, DNBError::POSIX);
+ if (DNBLogCheckLogBit(LOG_PROCESS) || m_err.Fail())
+ m_err.LogThreaded("::ptrace (PT_DETACH, %u, (caddr_t)1, 0)", pid);
+
+ // Resume our task
+ m_task.Resume();
+
+ SetState(eStateDetached);
+
+ // NULL our task out as we have already retored all exception ports
+ m_task.Clear();
+
+ // Clear out any notion of the process we once were
+ Clear();
+ return true;
+}
+
+
+nub_size_t
+MachProcess::RemoveTrapsFromBuffer (nub_addr_t addr, nub_size_t size, uint8_t *buf) const
+{
+ nub_size_t bytes_removed = 0;
+ const DNBBreakpoint *bp;
+ nub_addr_t intersect_addr;
+ nub_size_t intersect_size;
+ nub_size_t opcode_offset;
+ nub_size_t idx;
+ for (idx = 0; (bp = m_breakpoints.GetByIndex(idx)) != NULL; ++idx)
+ {
+ if (bp->IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset))
+ {
+ 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->ByteSize());
+ nub_size_t buf_offset = intersect_addr - addr;
+ ::memcpy(buf + buf_offset, bp->SavedOpcodeBytes() + opcode_offset, intersect_size);
+ }
+ }
+ return bytes_removed;
+}
+
+//----------------------------------------------------------------------
+// ReadMemory from the MachProcess level will always remove any software
+// breakpoints from the memory buffer before returning. If you wish to
+// read memory and see those traps, read from the MachTask
+// (m_task.ReadMemory()) as that version will give you what is actually
+// in inferior memory.
+//----------------------------------------------------------------------
+nub_size_t
+MachProcess::ReadMemory (nub_addr_t addr, nub_size_t size, void *buf)
+{
+ // We need to remove any current software traps (enabled software
+ // breakpoints) that we may have placed in our tasks memory.
+
+ // First just read the memory as is
+ nub_size_t bytes_read = m_task.ReadMemory(addr, size, buf);
+
+ // Then place any opcodes that fall into this range back into the buffer
+ // before we return this to callers.
+ if (bytes_read > 0)
+ RemoveTrapsFromBuffer (addr, size, (uint8_t *)buf);
+ return bytes_read;
+}
+
+//----------------------------------------------------------------------
+// WriteMemory from the MachProcess level will always write memory around
+// any software breakpoints. Any software breakpoints will have their
+// opcodes modified if they are enabled. Any memory that doesn't overlap
+// with software breakpoints will be written to. If you wish to write to
+// inferior memory without this interference, then write to the MachTask
+// (m_task.WriteMemory()) as that version will always modify inferior
+// memory.
+//----------------------------------------------------------------------
+nub_size_t
+MachProcess::WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf)
+{
+ // 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.
+
+ std::map<nub_addr_t, DNBBreakpoint *> addr_to_bp_map;
+ DNBBreakpoint *bp;
+ nub_size_t idx;
+ for (idx = 0; (bp = m_breakpoints.GetByIndex(idx)) != NULL; ++idx)
+ {
+ if (bp->IntersectsRange(addr, size, NULL, NULL, NULL))
+ addr_to_bp_map[bp->Address()] = bp;
+ }
+
+ // If we don't have any software breakpoints that are in this buffer, then
+ // we can just write memory and be done with it.
+ if (addr_to_bp_map.empty())
+ return m_task.WriteMemory(addr, size, buf);
+
+ // If we make it here, we have some breakpoints that overlap and we need
+ // to work around them.
+
+ nub_size_t bytes_written = 0;
+ nub_addr_t intersect_addr;
+ nub_size_t intersect_size;
+ nub_size_t opcode_offset;
+ const uint8_t *ubuf = (const uint8_t *)buf;
+ std::map<nub_addr_t, DNBBreakpoint *>::iterator pos, end = addr_to_bp_map.end();
+ for (pos = addr_to_bp_map.begin(); pos != end; ++pos)
+ {
+ bp = pos->second;
+
+ assert(bp->IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset));
+ 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->ByteSize());
+
+ // Check for bytes before this breakpoint
+ const nub_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
+ nub_size_t curr_size = intersect_addr - curr_addr;
+ nub_size_t curr_bytes_written = m_task.WriteMemory(curr_addr, curr_size, ubuf + bytes_written);
+ 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.
+ break;
+ }
+ }
+
+ // Now write any bytes that would cover up any software breakpoints
+ // directly into the breakpoint opcode buffer
+ ::memcpy(bp->SavedOpcodeBytes() + opcode_offset, ubuf + bytes_written, intersect_size);
+ bytes_written += intersect_size;
+ }
+
+ // Write any remaining bytes after the last breakpoint if we have any left
+ if (bytes_written < size)
+ bytes_written += m_task.WriteMemory(addr + bytes_written, size - bytes_written, ubuf + bytes_written);
+
+ return bytes_written;
+}
+
+
+void
+MachProcess::ReplyToAllExceptions (const DNBThreadResumeActions& thread_actions)
+{
+ PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex);
+ if (m_exception_messages.empty() == false)
+ {
+ MachException::Message::iterator pos;
+ MachException::Message::iterator begin = m_exception_messages.begin();
+ MachException::Message::iterator end = m_exception_messages.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "Replying to exception %d...", std::distance(begin, pos));
+ int thread_reply_signal = 0;
+
+ const DNBThreadResumeAction *action = thread_actions.GetActionForThread (pos->state.thread_port, false);
+
+ if (action)
+ {
+ thread_reply_signal = action->signal;
+ if (thread_reply_signal)
+ thread_actions.SetSignalHandledForThread (pos->state.thread_port);
+ }
+
+ m_err = pos->Reply(this, thread_reply_signal);
+ if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
+ m_err.LogThreadedIfError("Error replying to exception");
+ }
+
+ // Erase all exception message as we should have used and replied
+ // to them all already.
+ m_exception_messages.clear();
+ }
+}
+void
+MachProcess::PrivateResume (const DNBThreadResumeActions& thread_actions)
+{
+ PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
+
+ ReplyToAllExceptions (thread_actions);
+// bool stepOverBreakInstruction = step;
+
+ // Let the thread prepare to resume and see if any threads want us to
+ // step over a breakpoint instruction (ProcessWillResume will modify
+ // the value of stepOverBreakInstruction).
+ m_threadList.ProcessWillResume (this, thread_actions);
+
+ // Set our state accordingly
+ if (thread_actions.NumActionsWithState(eStateStepping))
+ SetState (eStateStepping);
+ else
+ SetState (eStateRunning);
+
+ // Now resume our task.
+ m_err = m_task.Resume();
+
+}
+
+nub_break_t
+MachProcess::CreateBreakpoint(nub_addr_t addr, nub_size_t length, bool hardware, thread_t tid)
+{
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::CreateBreakpoint ( addr = 0x%8.8llx, length = %u, hardware = %i, tid = 0x%4.4x )", (uint64_t)addr, length, hardware, tid);
+ if (hardware && tid == INVALID_NUB_THREAD)
+ tid = GetCurrentThread();
+
+ DNBBreakpoint bp(addr, length, tid, hardware);
+ nub_break_t breakID = m_breakpoints.Add(bp);
+ if (EnableBreakpoint(breakID))
+ {
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::CreateBreakpoint ( addr = 0x%8.8llx, length = %u, tid = 0x%4.4x ) => %u", (uint64_t)addr, length, tid, breakID);
+ return breakID;
+ }
+ else
+ {
+ m_breakpoints.Remove(breakID);
+ }
+ // We failed to enable the breakpoint
+ return INVALID_NUB_BREAK_ID;
+}
+
+nub_watch_t
+MachProcess::CreateWatchpoint(nub_addr_t addr, nub_size_t length, uint32_t watch_flags, bool hardware, thread_t tid)
+{
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = 0x%8.8llx, length = %u, flags = 0x%8.8x, hardware = %i, tid = 0x%4.4x )", (uint64_t)addr, length, watch_flags, hardware, tid);
+ if (hardware && tid == INVALID_NUB_THREAD)
+ tid = GetCurrentThread();
+
+ DNBBreakpoint watch(addr, length, tid, hardware);
+ watch.SetIsWatchpoint(watch_flags);
+
+ nub_watch_t watchID = m_watchpoints.Add(watch);
+ if (EnableWatchpoint(watchID))
+ {
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = 0x%8.8llx, length = %u, tid = 0x%x) => %u", (uint64_t)addr, length, tid, watchID);
+ return watchID;
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = 0x%8.8llx, length = %u, tid = 0x%x) => FAILED (%u)", (uint64_t)addr, length, tid, watchID);
+ m_watchpoints.Remove(watchID);
+ }
+ // We failed to enable the watchpoint
+ return INVALID_NUB_BREAK_ID;
+}
+
+nub_size_t
+MachProcess::DisableAllBreakpoints(bool remove)
+{
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::%s (remove = %d )", __FUNCTION__, remove);
+ DNBBreakpoint *bp;
+ nub_size_t disabled_count = 0;
+ nub_size_t idx = 0;
+ while ((bp = m_breakpoints.GetByIndex(idx)) != NULL)
+ {
+ bool success = DisableBreakpoint(bp->GetID(), remove);
+
+ if (success)
+ disabled_count++;
+ // If we failed to disable the breakpoint or we aren't removing the breakpoint
+ // increment the breakpoint index. Otherwise DisableBreakpoint will have removed
+ // the breakpoint at this index and we don't need to change it.
+ if ((success == false) || (remove == false))
+ idx++;
+ }
+ return disabled_count;
+}
+
+nub_size_t
+MachProcess::DisableAllWatchpoints(bool remove)
+{
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::%s (remove = %d )", __FUNCTION__, remove);
+ DNBBreakpoint *wp;
+ nub_size_t disabled_count = 0;
+ nub_size_t idx = 0;
+ while ((wp = m_watchpoints.GetByIndex(idx)) != NULL)
+ {
+ bool success = DisableWatchpoint(wp->GetID(), remove);
+
+ if (success)
+ disabled_count++;
+ // If we failed to disable the watchpoint or we aren't removing the watchpoint
+ // increment the watchpoint index. Otherwise DisableWatchpoint will have removed
+ // the watchpoint at this index and we don't need to change it.
+ if ((success == false) || (remove == false))
+ idx++;
+ }
+ return disabled_count;
+}
+
+bool
+MachProcess::DisableBreakpoint(nub_break_t breakID, bool remove)
+{
+ DNBBreakpoint *bp = m_breakpoints.FindByID (breakID);
+ if (bp)
+ {
+ nub_addr_t addr = bp->Address();
+ DNBLogThreadedIf(LOG_BREAKPOINTS | LOG_VERBOSE, "MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx", breakID, remove, (uint64_t)addr);
+
+ if (bp->IsHardware())
+ {
+ bool hw_disable_result = m_threadList.DisableHardwareBreakpoint (bp);
+
+ if (hw_disable_result == true)
+ {
+ bp->SetEnabled(false);
+ // Let the thread list know that a breakpoint has been modified
+ if (remove)
+ {
+ m_threadList.NotifyBreakpointChanged(bp);
+ m_breakpoints.Remove(breakID);
+ }
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx (hardware) => success", breakID, remove, (uint64_t)addr);
+ return true;
+ }
+
+ return false;
+ }
+
+ const nub_size_t break_op_size = bp->ByteSize();
+ assert (break_op_size > 0);
+ const uint8_t * const break_op = DNBArch::SoftwareBreakpointOpcode(bp->ByteSize());
+ if (break_op_size > 0)
+ {
+ // Clear a software breakoint instruction
+ uint8_t curr_break_op[break_op_size];
+ bool break_op_found = false;
+
+ // Read the breakpoint opcode
+ if (m_task.ReadMemory(addr, break_op_size, curr_break_op) == break_op_size)
+ {
+ bool verify = false;
+ if (bp->IsEnabled())
+ {
+ // 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 (m_task.WriteMemory(addr, break_op_size, bp->SavedOpcodeBytes()) == break_op_size)
+ {
+ verify = true;
+ }
+ else
+ {
+ DNBLogError("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx memory write failed when restoring original opcode", breakID, remove, (uint64_t)addr);
+ }
+ }
+ else
+ {
+ DNBLogWarning("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx expected a breakpoint opcode but didn't find one.", breakID, remove, (uint64_t)addr);
+ // Set verify to true and so we can check if the original opcode has already been restored
+ verify = true;
+ }
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_BREAKPOINTS | LOG_VERBOSE, "MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x$8.8llx is not enabled", breakID, remove, (uint64_t)addr);
+ // Set verify to true and so we can check if the original opcode is there
+ verify = true;
+ }
+
+ if (verify)
+ {
+ uint8_t verify_opcode[break_op_size];
+ // Verify that our original opcode made it back to the inferior
+ if (m_task.ReadMemory(addr, break_op_size, verify_opcode) == break_op_size)
+ {
+ // compare the memory we just read with the original opcode
+ if (memcmp(bp->SavedOpcodeBytes(), verify_opcode, break_op_size) == 0)
+ {
+ // SUCCESS
+ bp->SetEnabled(false);
+ // Let the thread list know that a breakpoint has been modified
+ if (remove)
+ {
+ m_threadList.NotifyBreakpointChanged(bp);
+ m_breakpoints.Remove(breakID);
+ }
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx => success", breakID, remove, (uint64_t)addr);
+ return true;
+ }
+ else
+ {
+ if (break_op_found)
+ DNBLogError("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx: failed to restore original opcode", breakID, remove, (uint64_t)addr);
+ else
+ DNBLogError("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx: opcode changed", breakID, remove, (uint64_t)addr);
+ }
+ }
+ else
+ {
+ DNBLogWarning("MachProcess::DisableBreakpoint: unable to disable breakpoint 0x%8.8llx", (uint64_t)addr);
+ }
+ }
+ }
+ else
+ {
+ DNBLogWarning("MachProcess::DisableBreakpoint: unable to read memory at 0x%8.8llx", (uint64_t)addr);
+ }
+ }
+ }
+ else
+ {
+ DNBLogError("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) invalid breakpoint ID", breakID, remove);
+ }
+ return false;
+}
+
+bool
+MachProcess::DisableWatchpoint(nub_watch_t watchID, bool remove)
+{
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::%s(watchID = %d, remove = %d)", __FUNCTION__, watchID, remove);
+ DNBBreakpoint *wp = m_watchpoints.FindByID (watchID);
+ if (wp)
+ {
+ nub_addr_t addr = wp->Address();
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::DisableWatchpoint ( watchID = %d, remove = %d ) addr = 0x%8.8llx", watchID, remove, (uint64_t)addr);
+
+ if (wp->IsHardware())
+ {
+ bool hw_disable_result = m_threadList.DisableHardwareWatchpoint (wp);
+
+ if (hw_disable_result == true)
+ {
+ wp->SetEnabled(false);
+ if (remove)
+ m_watchpoints.Remove(watchID);
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::Disablewatchpoint ( watchID = %d, remove = %d ) addr = 0x%8.8llx (hardware) => success", watchID, remove, (uint64_t)addr);
+ return true;
+ }
+ }
+
+ // TODO: clear software watchpoints if we implement them
+ }
+ else
+ {
+ DNBLogError("MachProcess::DisableWatchpoint ( watchID = %d, remove = %d ) invalid watchpoint ID", watchID, remove);
+ }
+ return false;
+}
+
+
+void
+MachProcess::DumpBreakpoint(nub_break_t breakID) const
+{
+ DNBLogThreaded("MachProcess::DumpBreakpoint(breakID = %d)", breakID);
+
+ if (NUB_BREAK_ID_IS_VALID(breakID))
+ {
+ const DNBBreakpoint *bp = m_breakpoints.FindByID(breakID);
+ if (bp)
+ bp->Dump();
+ else
+ DNBLog("MachProcess::DumpBreakpoint(breakID = %d): invalid breakID", breakID);
+ }
+ else
+ {
+ m_breakpoints.Dump();
+ }
+}
+
+void
+MachProcess::DumpWatchpoint(nub_watch_t watchID) const
+{
+ DNBLogThreaded("MachProcess::DumpWatchpoint(watchID = %d)", watchID);
+
+ if (NUB_BREAK_ID_IS_VALID(watchID))
+ {
+ const DNBBreakpoint *wp = m_watchpoints.FindByID(watchID);
+ if (wp)
+ wp->Dump();
+ else
+ DNBLog("MachProcess::DumpWatchpoint(watchID = %d): invalid watchID", watchID);
+ }
+ else
+ {
+ m_watchpoints.Dump();
+ }
+}
+
+bool
+MachProcess::EnableBreakpoint(nub_break_t breakID)
+{
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::EnableBreakpoint ( breakID = %d )", breakID);
+ DNBBreakpoint *bp = m_breakpoints.FindByID (breakID);
+ if (bp)
+ {
+ nub_addr_t addr = bp->Address();
+ if (bp->IsEnabled())
+ {
+ DNBLogWarning("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: breakpoint already enabled.", breakID, (uint64_t)addr);
+ return true;
+ }
+ else
+ {
+ if (bp->HardwarePreferred())
+ {
+ bp->SetHardwareIndex(m_threadList.EnableHardwareBreakpoint(bp));
+ if (bp->IsHardware())
+ {
+ bp->SetEnabled(true);
+ return true;
+ }
+ }
+
+ const nub_size_t break_op_size = bp->ByteSize();
+ assert (break_op_size != 0);
+ const uint8_t * const break_op = DNBArch::SoftwareBreakpointOpcode(break_op_size);
+ if (break_op_size > 0)
+ {
+ // Save the original opcode by reading it
+ if (m_task.ReadMemory(addr, break_op_size, bp->SavedOpcodeBytes()) == break_op_size)
+ {
+ // Write a software breakpoint in place of the original opcode
+ if (m_task.WriteMemory(addr, break_op_size, break_op) == break_op_size)
+ {
+ uint8_t verify_break_op[4];
+ if (m_task.ReadMemory(addr, break_op_size, verify_break_op) == break_op_size)
+ {
+ if (memcmp(break_op, verify_break_op, break_op_size) == 0)
+ {
+ bp->SetEnabled(true);
+ // Let the thread list know that a breakpoint has been modified
+ m_threadList.NotifyBreakpointChanged(bp);
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: SUCCESS.", breakID, (uint64_t)addr);
+ return true;
+ }
+ else
+ {
+ DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: breakpoint opcode verification failed.", breakID, (uint64_t)addr);
+ }
+ }
+ else
+ {
+ DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: unable to read memory to verify breakpoint opcode.", breakID, (uint64_t)addr);
+ }
+ }
+ else
+ {
+ DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: unable to write breakpoint opcode to memory.", breakID, (uint64_t)addr);
+ }
+ }
+ else
+ {
+ DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: unable to read memory at breakpoint address.", breakID, (uint64_t)addr);
+ }
+ }
+ else
+ {
+ DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) no software breakpoint opcode for current architecture.", breakID);
+ }
+ }
+ }
+ return false;
+}
+
+bool
+MachProcess::EnableWatchpoint(nub_watch_t watchID)
+{
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::EnableWatchpoint(watchID = %d)", watchID);
+ DNBBreakpoint *wp = m_watchpoints.FindByID (watchID);
+ if (wp)
+ {
+ nub_addr_t addr = wp->Address();
+ if (wp->IsEnabled())
+ {
+ DNBLogWarning("MachProcess::EnableWatchpoint(watchID = %d) addr = 0x%8.8llx: watchpoint already enabled.", watchID, (uint64_t)addr);
+ return true;
+ }
+ else
+ {
+ // Currently only try and set hardware watchpoints.
+ wp->SetHardwareIndex(m_threadList.EnableHardwareWatchpoint(wp));
+ if (wp->IsHardware())
+ {
+ wp->SetEnabled(true);
+ return true;
+ }
+ // TODO: Add software watchpoints by doing page protection tricks.
+ }
+ }
+ return false;
+}
+
+// Called by the exception thread when an exception has been received from
+// our process. The exception message is completely filled and the exception
+// data has already been copied.
+void
+MachProcess::ExceptionMessageReceived (const MachException::Message& exceptionMessage)
+{
+ PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
+
+ if (m_exception_messages.empty())
+ m_task.Suspend();
+
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "MachProcess::ExceptionMessageReceived ( )");
+
+ // Use a locker to automatically unlock our mutex in case of exceptions
+ // Add the exception to our internal exception stack
+ m_exception_messages.push_back(exceptionMessage);
+}
+
+void
+MachProcess::ExceptionMessageBundleComplete()
+{
+ // We have a complete bundle of exceptions for our child process.
+ PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "%s: %d exception messages.", __PRETTY_FUNCTION__, m_exception_messages.size());
+ if (!m_exception_messages.empty())
+ {
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ m_threadList.ProcessDidStop(this);
+
+ // Let each thread know of any exceptions
+ task_t task = m_task.TaskPort();
+ size_t i;
+ for (i=0; i<m_exception_messages.size(); ++i)
+ {
+ // Let the thread list figure use the MachProcess to forward all exceptions
+ // on down to each thread.
+ if (m_exception_messages[i].state.task_port == task)
+ m_threadList.NotifyException(m_exception_messages[i].state);
+ if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
+ m_exception_messages[i].Dump();
+ }
+
+ if (DNBLogCheckLogBit(LOG_THREAD))
+ m_threadList.Dump();
+
+ bool step_more = false;
+ if (m_threadList.ShouldStop(step_more))
+ {
+ // Wait for the eEventProcessRunningStateChanged event to be reset
+ // before changing state to stopped to avoid race condition with
+ // very fast start/stops
+ struct timespec timeout;
+ //DNBTimer::OffsetTimeOfDay(&timeout, 0, 250 * 1000); // Wait for 250 ms
+ DNBTimer::OffsetTimeOfDay(&timeout, 1, 0); // Wait for 250 ms
+ m_events.WaitForEventsToReset(eEventProcessRunningStateChanged, &timeout);
+ SetState(eStateStopped);
+ }
+ else
+ {
+ // Resume without checking our current state.
+ PrivateResume (DNBThreadResumeActions (eStateRunning, 0));
+ }
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "%s empty exception messages bundle.", __PRETTY_FUNCTION__, m_exception_messages.size());
+ }
+}
+
+nub_size_t
+MachProcess::CopyImageInfos ( struct DNBExecutableImageInfo **image_infos, bool only_changed)
+{
+ if (m_image_infos_callback != NULL)
+ return m_image_infos_callback(ProcessID(), image_infos, only_changed, m_image_infos_baton);
+ return 0;
+}
+
+void
+MachProcess::SharedLibrariesUpdated ( )
+{
+ uint32_t event_bits = eEventSharedLibsStateChange;
+ // Set the shared library event bit to let clients know of shared library
+ // changes
+ m_events.SetEvents(event_bits);
+ // Wait for the event bit to reset if a reset ACK is requested
+ m_events.WaitForResetAck(event_bits);
+}
+
+void
+MachProcess::AppendSTDOUT (char* s, size_t len)
+{
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (<%d> %s) ...", __FUNCTION__, len, s);
+ PTHREAD_MUTEX_LOCKER (locker, m_stdio_mutex);
+ m_stdout_data.append(s, len);
+ m_events.SetEvents(eEventStdioAvailable);
+
+ // Wait for the event bit to reset if a reset ACK is requested
+ m_events.WaitForResetAck(eEventStdioAvailable);
+}
+
+size_t
+MachProcess::GetAvailableSTDOUT (char *buf, size_t buf_size)
+{
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (&%p[%u]) ...", __FUNCTION__, buf, buf_size);
+ PTHREAD_MUTEX_LOCKER (locker, m_stdio_mutex);
+ size_t bytes_available = m_stdout_data.size();
+ if (bytes_available > 0)
+ {
+ if (bytes_available > buf_size)
+ {
+ memcpy(buf, m_stdout_data.data(), buf_size);
+ m_stdout_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ }
+ else
+ {
+ memcpy(buf, m_stdout_data.data(), bytes_available);
+ m_stdout_data.clear();
+ }
+ }
+ return bytes_available;
+}
+
+nub_addr_t
+MachProcess::GetDYLDAllImageInfosAddress ()
+{
+ return m_task.GetDYLDAllImageInfosAddress(m_err);
+}
+
+size_t
+MachProcess::GetAvailableSTDERR (char *buf, size_t buf_size)
+{
+ return 0;
+}
+
+void *
+MachProcess::STDIOThread(void *arg)
+{
+ MachProcess *proc = (MachProcess*) arg;
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( arg = %p ) thread starting...", __FUNCTION__, arg);
+
+ // We start use a base and more options so we can control if we
+ // are currently using a timeout on the mach_msg. We do this to get a
+ // bunch of related exceptions on our exception port so we can process
+ // then together. When we have multiple threads, we can get an exception
+ // per thread and they will come in consecutively. The main thread loop
+ // will start by calling mach_msg to without having the MACH_RCV_TIMEOUT
+ // flag set in the options, so we will wait forever for an exception on
+ // our exception port. After we get one exception, we then will use the
+ // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current
+ // exceptions for our process. After we have received the last pending
+ // exception, we will get a timeout which enables us to then notify
+ // our main thread that we have an exception bundle avaiable. We then wait
+ // for the main thread to tell this exception thread to start trying to get
+ // exceptions messages again and we start again with a mach_msg read with
+ // infinite timeout.
+ DNBError err;
+ int stdout_fd = proc->GetStdoutFileDescriptor();
+ int stderr_fd = proc->GetStderrFileDescriptor();
+ if (stdout_fd == stderr_fd)
+ stderr_fd = -1;
+
+ while (stdout_fd >= 0 || stderr_fd >= 0)
+ {
+ ::pthread_testcancel ();
+
+ fd_set read_fds;
+ FD_ZERO (&read_fds);
+ if (stdout_fd >= 0)
+ FD_SET (stdout_fd, &read_fds);
+ if (stderr_fd >= 0)
+ FD_SET (stderr_fd, &read_fds);
+ int nfds = std::max<int>(stdout_fd, stderr_fd) + 1;
+
+ int num_set_fds = select (nfds, &read_fds, NULL, NULL, NULL);
+ DNBLogThreadedIf(LOG_PROCESS, "select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
+
+ if (num_set_fds < 0)
+ {
+ int select_errno = errno;
+ if (DNBLogCheckLogBit(LOG_PROCESS))
+ {
+ err.SetError (select_errno, DNBError::POSIX);
+ err.LogThreadedIfError("select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
+ }
+
+ switch (select_errno)
+ {
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to allocate the requested number of file descriptors, or we have non-blocking IO
+ break;
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ return NULL;
+ break;
+ case EINTR: // A signal was delivered before the time limit expired and before any of the selected events occurred.
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
+ break;
+ }
+ }
+ else if (num_set_fds == 0)
+ {
+ }
+ else
+ {
+ char s[1024];
+ s[sizeof(s)-1] = '\0'; // Ensure we have NULL termination
+ int bytes_read = 0;
+ if (stdout_fd >= 0 && FD_ISSET (stdout_fd, &read_fds))
+ {
+ do
+ {
+ bytes_read = ::read (stdout_fd, s, sizeof(s)-1);
+ if (bytes_read < 0)
+ {
+ int read_errno = errno;
+ DNBLogThreadedIf(LOG_PROCESS, "read (stdout_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
+ }
+ else if (bytes_read == 0)
+ {
+ // EOF...
+ DNBLogThreadedIf(LOG_PROCESS, "read (stdout_fd, ) => %d (reached EOF for child STDOUT)", bytes_read);
+ stdout_fd = -1;
+ }
+ else if (bytes_read > 0)
+ {
+ proc->AppendSTDOUT(s, bytes_read);
+ }
+
+ } while (bytes_read > 0);
+ }
+
+ if (stderr_fd >= 0 && FD_ISSET (stderr_fd, &read_fds))
+ {
+ do
+ {
+ bytes_read = ::read (stderr_fd, s, sizeof(s)-1);
+ if (bytes_read < 0)
+ {
+ int read_errno = errno;
+ DNBLogThreadedIf(LOG_PROCESS, "read (stderr_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
+ }
+ else if (bytes_read == 0)
+ {
+ // EOF...
+ DNBLogThreadedIf(LOG_PROCESS, "read (stderr_fd, ) => %d (reached EOF for child STDERR)", bytes_read);
+ stderr_fd = -1;
+ }
+ else if (bytes_read > 0)
+ {
+ proc->AppendSTDOUT(s, bytes_read);
+ }
+
+ } while (bytes_read > 0);
+ }
+ }
+ }
+ DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (%p): thread exiting...", __FUNCTION__, arg);
+ return NULL;
+}
+
+pid_t
+MachProcess::AttachForDebug (pid_t pid, char *err_str, size_t err_len)
+{
+ // Clear out and clean up from any current state
+ Clear();
+ if (pid != 0)
+ {
+ // Make sure the process exists...
+ if (::getpgid (pid) < 0)
+ {
+ m_err.SetErrorToErrno();
+ const char *err_cstr = m_err.AsString();
+ ::snprintf (err_str, err_len, "%s", err_cstr ? err_cstr : "No such process");
+ return INVALID_NUB_PROCESS;
+ }
+
+ SetState(eStateAttaching);
+ m_pid = pid;
+ // Let ourselves know we are going to be using SBS if the correct flag bit is set...
+#if defined (__arm__)
+ if (IsSBProcess(pid))
+ m_flags |= eMachProcessFlagsUsingSBS;
+#endif
+ if (!m_task.StartExceptionThread(m_err))
+ {
+ const char *err_cstr = m_err.AsString();
+ ::snprintf (err_str, err_len, "%s", err_cstr ? err_cstr : "unable to start the exception thread");
+ DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", pid);
+ m_pid = INVALID_NUB_PROCESS;
+ return INVALID_NUB_PROCESS;
+ }
+
+ errno = 0;
+ int err = ptrace (PT_ATTACHEXC, pid, 0, 0);
+
+ if (err < 0)
+ m_err.SetError(errno);
+ else
+ m_err.Clear();
+
+ if (m_err.Success())
+ {
+ m_flags |= eMachProcessFlagsAttached;
+ // Sleep a bit to let the exception get received and set our process status
+ // to stopped.
+ ::usleep(250000);
+ DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", pid);
+ return m_pid;
+ }
+ else
+ {
+ ::snprintf (err_str, err_len, "%s", m_err.AsString());
+ DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", pid);
+ }
+ }
+ return INVALID_NUB_PROCESS;
+}
+
+// Do the process specific setup for attach. If this returns NULL, then there's no
+// platform specific stuff to be done to wait for the attach. If you get non-null,
+// pass that token to the CheckForProcess method, and then to CleanupAfterAttach.
+
+// Call PrepareForAttach before attaching to a process that has not yet launched
+// This returns a token that can be passed to CheckForProcess, and to CleanupAfterAttach.
+// You should call CleanupAfterAttach to free the token, and do whatever other
+// cleanup seems good.
+
+const void *
+MachProcess::PrepareForAttach (const char *path, nub_launch_flavor_t launch_flavor, bool waitfor, DNBError &err_str)
+{
+#if defined (__arm__)
+ // Tell SpringBoard to halt the next launch of this application on startup.
+
+ if (!waitfor)
+ return NULL;
+
+ const char *app_ext = strstr(path, ".app");
+ if (app_ext == NULL)
+ {
+ DNBLogThreadedIf(LOG_PROCESS, "%s: path '%s' doesn't contain .app, we can't tell springboard to wait for launch...", path);
+ return NULL;
+ }
+
+ if (launch_flavor != eLaunchFlavorSpringBoard
+ && launch_flavor != eLaunchFlavorDefault)
+ return NULL;
+
+ std::string app_bundle_path(path, app_ext + strlen(".app"));
+
+ CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path.c_str (), err_str);
+ std::string bundleIDStr;
+ CFString::UTF8(bundleIDCFStr, bundleIDStr);
+ DNBLogThreadedIf(LOG_PROCESS, "CopyBundleIDForPath (%s, err_str) returned @\"%s\"", app_bundle_path.c_str (), bundleIDStr.c_str());
+
+ if (bundleIDCFStr == NULL)
+ {
+ return NULL;
+ }
+
+ SBSApplicationLaunchError sbs_error = 0;
+
+ const char *stdout_err = "/dev/null";
+ CFString stdio_path;
+ stdio_path.SetFileSystemRepresentation (stdout_err);
+
+ DNBLogThreadedIf(LOG_PROCESS, "SBSLaunchApplicationForDebugging ( @\"%s\" , NULL, NULL, NULL, @\"%s\", @\"%s\", SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger )", bundleIDStr.c_str(), stdout_err, stdout_err);
+ sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr,
+ (CFURLRef)NULL, // openURL
+ NULL, // launch_argv.get(),
+ NULL, // launch_envp.get(), // CFDictionaryRef environment
+ stdio_path.get(),
+ stdio_path.get(),
+ SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger);
+
+ if (sbs_error != SBSApplicationLaunchErrorSuccess)
+ {
+ err_str.SetError(sbs_error, DNBError::SpringBoard);
+ return NULL;
+ }
+
+ DNBLogThreadedIf(LOG_PROCESS, "Successfully set DebugOnNextLaunch.");
+ return bundleIDCFStr;
+# else
+ return NULL;
+#endif
+}
+
+// Pass in the token you got from PrepareForAttach. If there is a process
+// for that token, then the pid will be returned, otherwise INVALID_NUB_PROCESS
+// will be returned.
+
+nub_process_t
+MachProcess::CheckForProcess (const void *attach_token)
+{
+ if (attach_token == NULL)
+ return INVALID_NUB_PROCESS;
+
+#if defined (__arm__)
+ CFStringRef bundleIDCFStr = (CFStringRef) attach_token;
+ Boolean got_it;
+ nub_process_t attach_pid;
+ got_it = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &attach_pid);
+ if (got_it)
+ return attach_pid;
+ else
+ return INVALID_NUB_PROCESS;
+#endif
+ return INVALID_NUB_PROCESS;
+}
+
+// Call this to clean up after you have either attached or given up on the attach.
+// Pass true for success if you have attached, false if you have not.
+// The token will also be freed at this point, so you can't use it after calling
+// this method.
+
+void
+MachProcess::CleanupAfterAttach (const void *attach_token, bool success, DNBError &err_str)
+{
+#if defined (__arm__)
+ if (attach_token == NULL)
+ return;
+
+ // Tell SpringBoard to cancel the debug on next launch of this application
+ // if we failed to attach
+ if (!success)
+ {
+ SBSApplicationLaunchError sbs_error = 0;
+ CFStringRef bundleIDCFStr = (CFStringRef) attach_token;
+
+ sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr,
+ (CFURLRef)NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SBSApplicationCancelDebugOnNextLaunch);
+
+ if (sbs_error != SBSApplicationLaunchErrorSuccess)
+ {
+ err_str.SetError(sbs_error, DNBError::SpringBoard);
+ return;
+ }
+ }
+
+ CFRelease((CFStringRef) attach_token);
+#endif
+}
+
+pid_t
+MachProcess::LaunchForDebug
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ const char *stdio_path,
+ nub_launch_flavor_t launch_flavor,
+ DNBError &launch_err
+)
+{
+ // Clear out and clean up from any current state
+ Clear();
+
+ DNBLogThreadedIf(LOG_PROCESS, "%s( path = '%s', argv = %p, envp = %p, launch_flavor = %u )", __FUNCTION__, path, argv, envp, launch_flavor);
+
+ // Fork a child process for debugging
+ SetState(eStateLaunching);
+
+ switch (launch_flavor)
+ {
+ case eLaunchFlavorForkExec:
+ m_pid = MachProcess::ForkChildForPTraceDebugging (path, argv, envp, this, launch_err);
+ break;
+
+ case eLaunchFlavorPosixSpawn:
+ m_pid = MachProcess::PosixSpawnChildForPTraceDebugging (path, argv, envp, stdio_path, this, launch_err);
+ break;
+
+#if defined (__arm__)
+
+ case eLaunchFlavorSpringBoard:
+ {
+ const char *app_ext = strstr(path, ".app");
+ if (app_ext != NULL)
+ {
+ std::string app_bundle_path(path, app_ext + strlen(".app"));
+ return SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, launch_err);
+ }
+ }
+ break;
+
+#endif
+
+ default:
+ // Invalid launch
+ launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic);
+ return INVALID_NUB_PROCESS;
+ }
+
+ if (m_pid == INVALID_NUB_PROCESS)
+ {
+ // If we don't have a valid process ID and no one has set the error,
+ // then return a generic error
+ if (launch_err.Success())
+ launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic);
+ }
+ else
+ {
+ m_path = path;
+ size_t i;
+ char const *arg;
+ for (i=0; (arg = argv[i]) != NULL; i++)
+ m_args.push_back(arg);
+
+ m_task.StartExceptionThread(m_err);
+ if (m_err.Fail())
+ {
+ if (m_err.AsString() == NULL)
+ m_err.SetErrorString("unable to start the exception thread");
+ ::ptrace (PT_KILL, m_pid, 0, 0);
+ m_pid = INVALID_NUB_PROCESS;
+ return INVALID_NUB_PROCESS;
+ }
+
+ StartSTDIOThread();
+
+ if (launch_flavor == eLaunchFlavorPosixSpawn)
+ {
+
+ SetState (eStateAttaching);
+ errno = 0;
+ int err = ptrace (PT_ATTACHEXC, m_pid, 0, 0);
+ if (err == 0)
+ {
+ m_flags |= eMachProcessFlagsAttached;
+ DNBLogThreadedIf(LOG_PROCESS, "successfully spawned pid %d", m_pid);
+ launch_err.Clear();
+ }
+ else
+ {
+ SetState (eStateExited);
+ DNBError ptrace_err(errno, DNBError::POSIX);
+ DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to spawned pid %d (err = %i, errno = %i (%s))", m_pid, err, ptrace_err.Error(), ptrace_err.AsString());
+ launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic);
+ }
+ }
+ else
+ {
+ launch_err.Clear();
+ }
+ }
+ return m_pid;
+}
+
+pid_t
+MachProcess::PosixSpawnChildForPTraceDebugging
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ const char *stdio_path,
+ MachProcess* process,
+ DNBError& err
+)
+{
+ posix_spawnattr_t attr;
+ DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv=%p, envp=%p, process )", __FUNCTION__, path, argv, envp);
+
+ err.SetError( ::posix_spawnattr_init (&attr), DNBError::POSIX);
+ if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
+ err.LogThreaded("::posix_spawnattr_init ( &attr )");
+ if (err.Fail())
+ return INVALID_NUB_PROCESS;
+
+ err.SetError( ::posix_spawnattr_setflags (&attr, POSIX_SPAWN_START_SUSPENDED), DNBError::POSIX);
+ if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
+ err.LogThreaded("::posix_spawnattr_setflags ( &attr, POSIX_SPAWN_START_SUSPENDED )");
+ if (err.Fail())
+ return INVALID_NUB_PROCESS;
+
+ // Don't do this on SnowLeopard, _sometimes_ the TASK_BASIC_INFO will fail
+ // and we will fail to continue with our process...
+
+ // On SnowLeopard we should set "DYLD_NO_PIE" in the inferior environment....
+
+//#ifndef _POSIX_SPAWN_DISABLE_ASLR
+//#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
+//#endif
+// err.SetError( ::posix_spawnattr_setflags (&attr, _POSIX_SPAWN_DISABLE_ASLR), DNBError::POSIX);
+// if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
+// err.LogThreaded("::posix_spawnattr_setflags ( &attr, _POSIX_SPAWN_DISABLE_ASLR )");
+
+#if !defined(__arm__)
+
+ // We don't need to do this for ARM, and we really shouldn't now that we
+ // have multiple CPU subtypes and no posix_spawnattr call that allows us
+ // to set which CPU subtype to launch...
+ cpu_type_t cpu_type = DNBArch::GetCPUType();
+ size_t ocount = 0;
+ err.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu_type, &ocount), DNBError::POSIX);
+ if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
+ err.LogThreaded("::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %zu )", cpu_type, ocount);
+
+ if (err.Fail() != 0 || ocount != 1)
+ return INVALID_NUB_PROCESS;
+
+#endif
+
+ PseudoTerminal pty;
+
+ posix_spawn_file_actions_t file_actions;
+ err.SetError( ::posix_spawn_file_actions_init (&file_actions), DNBError::POSIX);
+ int file_actions_valid = err.Success();
+ if (!file_actions_valid || DNBLogCheckLogBit(LOG_PROCESS))
+ err.LogThreaded("::posix_spawn_file_actions_init ( &file_actions )");
+ int pty_error = -1;
+ pid_t pid = INVALID_NUB_PROCESS;
+ if (file_actions_valid)
+ {
+ if (stdio_path == NULL)
+ {
+ pty_error = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY);
+ if (pty_error == PseudoTerminal::success)
+ stdio_path = pty.SlaveName();
+ // Make sure we were able to get the slave name
+ if (stdio_path == NULL)
+ stdio_path = "/dev/null";
+ }
+
+ if (stdio_path != NULL)
+ {
+ err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDERR_FILENO, stdio_path, O_RDWR, 0), DNBError::POSIX);
+ if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
+ err.LogThreaded("::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDERR_FILENO, path = '%s', oflag = O_RDWR, mode = 0 )", stdio_path);
+
+ err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDIN_FILENO, stdio_path, O_RDONLY, 0), DNBError::POSIX);
+ if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
+ err.LogThreaded("::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDIN_FILENO, path = '%s', oflag = O_RDONLY, mode = 0 )", stdio_path);
+
+ err.SetError( ::posix_spawn_file_actions_addopen(&file_actions, STDOUT_FILENO, stdio_path, O_WRONLY, 0), DNBError::POSIX);
+ if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
+ err.LogThreaded("::posix_spawn_file_actions_addopen ( &file_actions, filedes = STDOUT_FILENO, path = '%s', oflag = O_WRONLY, mode = 0 )", stdio_path);
+ }
+ err.SetError( ::posix_spawnp (&pid, path, &file_actions, &attr, (char * const*)argv, (char * const*)envp), DNBError::POSIX);
+ if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
+ err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, &file_actions, &attr, argv, envp);
+ }
+ else
+ {
+ err.SetError( ::posix_spawnp (&pid, path, NULL, &attr, (char * const*)argv, (char * const*)envp), DNBError::POSIX);
+ if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
+ err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, NULL, &attr, argv, envp);
+ }
+
+ // We have seen some cases where posix_spawnp was returning a valid
+ // looking pid even when an error was returned, so clear it out
+ if (err.Fail())
+ pid = INVALID_NUB_PROCESS;
+
+ if (pty_error == 0)
+ {
+ if (process != NULL)
+ {
+ int master_fd = pty.ReleaseMasterFD();
+ process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
+ }
+ }
+
+ if (file_actions_valid)
+ {
+ DNBError err2;
+ err2.SetError( ::posix_spawn_file_actions_destroy (&file_actions), DNBError::POSIX);
+ if (err2.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
+ err2.LogThreaded("::posix_spawn_file_actions_destroy ( &file_actions )");
+ }
+
+ return pid;
+}
+
+pid_t
+MachProcess::ForkChildForPTraceDebugging
+(
+ const char *path,
+ char const *argv[],
+ char const *envp[],
+ MachProcess* process,
+ DNBError& launch_err
+)
+{
+ PseudoTerminal::Error pty_error = PseudoTerminal::success;
+
+ // Use a fork that ties the child process's stdin/out/err to a pseudo
+ // terminal so we can read it in our MachProcess::STDIOThread
+ // as unbuffered io.
+ PseudoTerminal pty;
+ pid_t pid = pty.Fork(pty_error);
+
+ if (pid < 0)
+ {
+ //--------------------------------------------------------------
+ // Error during fork.
+ //--------------------------------------------------------------
+ return pid;
+ }
+ else if (pid == 0)
+ {
+ //--------------------------------------------------------------
+ // Child process
+ //--------------------------------------------------------------
+ ::ptrace (PT_TRACE_ME, 0, 0, 0); // Debug this process
+ ::ptrace (PT_SIGEXC, 0, 0, 0); // Get BSD signals as mach exceptions
+
+ // If our parent is setgid, lets make sure we don't inherit those
+ // extra powers due to nepotism.
+ ::setgid (getgid ());
+
+ // Let the child have its own process group. We need to execute
+ // this call in both the child and parent to avoid a race condition
+ // between the two processes.
+ ::setpgid (0, 0); // Set the child process group to match its pid
+
+ // Sleep a bit to before the exec call
+ ::sleep (1);
+
+ // Turn this process into
+ ::execv (path, (char * const *)argv);
+ // Exit with error code. Child process should have taken
+ // over in above exec call and if the exec fails it will
+ // exit the child process below.
+ ::exit (127);
+ }
+ else
+ {
+ //--------------------------------------------------------------
+ // Parent process
+ //--------------------------------------------------------------
+ // Let the child have its own process group. We need to execute
+ // this call in both the child and parent to avoid a race condition
+ // between the two processes.
+ ::setpgid (pid, pid); // Set the child process group to match its pid
+
+ if (process != NULL)
+ {
+ // Release our master pty file descriptor so the pty class doesn't
+ // close it and so we can continue to use it in our STDIO thread
+ int master_fd = pty.ReleaseMasterFD();
+ process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
+ }
+ }
+ return pid;
+}
+
+#if defined (__arm__)
+
+pid_t
+MachProcess::SBLaunchForDebug (const char *path, char const *argv[], char const *envp[], DNBError &launch_err)
+{
+ // Clear out and clean up from any current state
+ Clear();
+
+ DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path);
+
+ // Fork a child process for debugging
+ SetState(eStateLaunching);
+ m_pid = MachProcess::SBForkChildForPTraceDebugging(path, argv, envp, this, launch_err);
+ if (m_pid != 0)
+ {
+ m_flags |= eMachProcessFlagsUsingSBS;
+ m_path = path;
+ size_t i;
+ char const *arg;
+ for (i=0; (arg = argv[i]) != NULL; i++)
+ m_args.push_back(arg);
+ m_task.StartExceptionThread();
+ StartSTDIOThread();
+ SetState (eStateAttaching);
+ int err = ptrace (PT_ATTACHEXC, m_pid, 0, 0);
+ if (err == 0)
+ {
+ m_flags |= eMachProcessFlagsAttached;
+ DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", m_pid);
+ }
+ else
+ {
+ SetState (eStateExited);
+ DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", m_pid);
+ }
+ }
+ return m_pid;
+}
+
+#include <servers/bootstrap.h>
+
+// This returns a CFRetained pointer to the Bundle ID for app_bundle_path,
+// or NULL if there was some problem getting the bundle id.
+static CFStringRef
+CopyBundleIDForPath (const char *app_bundle_path, DNBError &err_str)
+{
+ CFBundle bundle(app_bundle_path);
+ CFStringRef bundleIDCFStr = bundle.GetIdentifier();
+ std::string bundleID;
+ if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL)
+ {
+ struct stat app_bundle_stat;
+ char err_msg[PATH_MAX];
+
+ if (::stat (app_bundle_path, &app_bundle_stat) < 0)
+ {
+ err_str.SetError(errno, DNBError::POSIX);
+ snprintf(err_msg, sizeof(err_msg), "%s: \"%s\"", err_str.AsString(), app_bundle_path);
+ err_str.SetErrorString(err_msg);
+ DNBLogThreadedIf(LOG_PROCESS, "%s() error: %s", __FUNCTION__, err_msg);
+ }
+ else
+ {
+ err_str.SetError(-1, DNBError::Generic);
+ snprintf(err_msg, sizeof(err_msg), "failed to extract CFBundleIdentifier from %s", app_bundle_path);
+ err_str.SetErrorString(err_msg);
+ DNBLogThreadedIf(LOG_PROCESS, "%s() error: failed to extract CFBundleIdentifier from '%s'", __FUNCTION__, app_bundle_path);
+ }
+ return NULL;
+ }
+
+ DNBLogThreadedIf(LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", __FUNCTION__, bundleID.c_str());
+ CFRetain (bundleIDCFStr);
+
+ return bundleIDCFStr;
+}
+
+pid_t
+MachProcess::SBForkChildForPTraceDebugging (const char *app_bundle_path, char const *argv[], char const *envp[], MachProcess* process, DNBError &launch_err)
+{
+ DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, app_bundle_path, process);
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+
+ if (argv[0] == NULL)
+ return INVALID_NUB_PROCESS;
+
+ size_t argc = 0;
+ // Count the number of arguments
+ while (argv[argc] != NULL)
+ argc++;
+
+ // Enumerate the arguments
+ size_t first_launch_arg_idx = 1;
+ CFReleaser<CFMutableArrayRef> launch_argv;
+
+ if (argv[first_launch_arg_idx])
+ {
+ size_t launch_argc = argc > 0 ? argc - 1 : 0;
+ launch_argv.reset (::CFArrayCreateMutable (alloc, launch_argc, &kCFTypeArrayCallBacks));
+ size_t i;
+ char const *arg;
+ CFString launch_arg;
+ for (i=first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); i++)
+ {
+ launch_arg.reset(::CFStringCreateWithCString (alloc, arg, kCFStringEncodingUTF8));
+ if (launch_arg.get() != NULL)
+ CFArrayAppendValue(launch_argv.get(), launch_arg.get());
+ else
+ break;
+ }
+ }
+
+ // Next fill in the arguments dictionary. Note, the envp array is of the form
+ // Variable=value but SpringBoard wants a CF dictionary. So we have to convert
+ // this here.
+
+ CFReleaser<CFMutableDictionaryRef> launch_envp;
+
+ if (envp[0])
+ {
+ launch_envp.reset(::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+ const char *value;
+ int name_len;
+ CFString name_string, value_string;
+
+ for (int i = 0; envp[i] != NULL; i++)
+ {
+ value = strstr (envp[i], "=");
+
+ // If the name field is empty or there's no =, skip it. Somebody's messing with us.
+ if (value == NULL || value == envp[i])
+ continue;
+
+ name_len = value - envp[i];
+
+ // Now move value over the "="
+ value++;
+
+ name_string.reset(::CFStringCreateWithBytes(alloc, (const UInt8 *) envp[i], name_len, kCFStringEncodingUTF8, false));
+ value_string.reset(::CFStringCreateWithCString(alloc, value, kCFStringEncodingUTF8));
+ CFDictionarySetValue (launch_envp.get(), name_string.get(), value_string.get());
+ }
+ }
+
+ CFString stdio_path;
+
+ PseudoTerminal pty;
+ PseudoTerminal::Error pty_err = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY);
+ if (pty_err == PseudoTerminal::success)
+ {
+ const char* slave_name = pty.SlaveName();
+ DNBLogThreadedIf(LOG_PROCESS, "%s() successfully opened master pty, slave is %s", __FUNCTION__, slave_name);
+ if (slave_name && slave_name[0])
+ {
+ ::chmod (slave_name, S_IRWXU | S_IRWXG | S_IRWXO);
+ stdio_path.SetFileSystemRepresentation (slave_name);
+ }
+ }
+
+ if (stdio_path.get() == NULL)
+ {
+ stdio_path.SetFileSystemRepresentation ("/dev/null");
+ }
+
+ CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path, launch_err);
+ if (bundleIDCFStr == NULL)
+ return INVALID_NUB_PROCESS;
+
+ std::string bundleID;
+ CFString::UTF8(bundleIDCFStr, bundleID);
+
+ CFData argv_data(NULL);
+
+ if (launch_argv.get())
+ {
+ if (argv_data.Serialize(launch_argv.get(), kCFPropertyListBinaryFormat_v1_0) == NULL)
+ {
+ DNBLogThreadedIf(LOG_PROCESS, "%s() error: failed to serialize launch arg array...", __FUNCTION__);
+ return INVALID_NUB_PROCESS;
+ }
+ }
+
+ DNBLogThreadedIf(LOG_PROCESS, "%s() serialized launch arg array", __FUNCTION__);
+
+ // Find SpringBoard
+ SBSApplicationLaunchError sbs_error = 0;
+ sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr,
+ (CFURLRef)NULL, // openURL
+ launch_argv.get(),
+ launch_envp.get(), // CFDictionaryRef environment
+ stdio_path.get(),
+ stdio_path.get(),
+ SBSApplicationLaunchWaitForDebugger | SBSApplicationLaunchUnlockDevice);
+
+
+ launch_err.SetError(sbs_error, DNBError::SpringBoard);
+
+ if (sbs_error == SBSApplicationLaunchErrorSuccess)
+ {
+ static const useconds_t pid_poll_interval = 200000;
+ static const useconds_t pid_poll_timeout = 30000000;
+
+ useconds_t pid_poll_total = 0;
+
+ nub_process_t pid = INVALID_NUB_PROCESS;
+ Boolean pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
+ // Poll until the process is running, as long as we are getting valid responses and the timeout hasn't expired
+ // A return PID of 0 means the process is not running, which may be because it hasn't been (asynchronously) started
+ // yet, or that it died very quickly (if you weren't using waitForDebugger).
+ while (!pid_found && pid_poll_total < pid_poll_timeout)
+ {
+ usleep (pid_poll_interval);
+ pid_poll_total += pid_poll_interval;
+ DNBLogThreadedIf(LOG_PROCESS, "%s() polling Springboard for pid for %s...", __FUNCTION__, bundleID.c_str());
+ pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
+ }
+
+ CFRelease (bundleIDCFStr);
+ if (pid_found)
+ {
+ if (process != NULL)
+ {
+ // Release our master pty file descriptor so the pty class doesn't
+ // close it and so we can continue to use it in our STDIO thread
+ int master_fd = pty.ReleaseMasterFD();
+ process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
+ }
+ DNBLogThreadedIf(LOG_PROCESS, "%s() => pid = %4.4x", __FUNCTION__, pid);
+ }
+ else
+ {
+ DNBLogError("failed to lookup the process ID for CFBundleIdentifier %s.", bundleID.c_str());
+ }
+ return pid;
+ }
+
+ DNBLogError("unable to launch the application with CFBundleIdentifier '%s' sbs_error = %u", bundleID.c_str(), sbs_error);
+ return INVALID_NUB_PROCESS;
+}
+
+#endif // #if defined (__arm__)
+
+
diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.h b/lldb/tools/debugserver/source/MacOSX/MachProcess.h
new file mode 100644
index 00000000000..4d5d0d4af92
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.h
@@ -0,0 +1,263 @@
+//===-- MachProcess.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/15/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __MachProcess_h__
+#define __MachProcess_h__
+
+#include "DNBDefs.h"
+#include "DNBBreakpoint.h"
+#include "DNBError.h"
+//#include "MachDYLD.h"
+#include "MachException.h"
+#include "MachVMMemory.h"
+#include "MachTask.h"
+#include "MachThreadList.h"
+#include "PThreadCondition.h"
+#include "PThreadEvent.h"
+#include "PThreadMutex.h"
+
+#include <mach/mach.h>
+#include <sys/signal.h>
+#include <pthread.h>
+#include <vector>
+
+class DNBThreadResumeActions;
+
+class MachProcess
+{
+public:
+ //----------------------------------------------------------------------
+ // Constructors and Destructors
+ //----------------------------------------------------------------------
+ MachProcess ();
+ ~MachProcess ();
+
+ //----------------------------------------------------------------------
+ // Child process control
+ //----------------------------------------------------------------------
+ pid_t AttachForDebug (pid_t pid, char *err_str, size_t err_len);
+ pid_t LaunchForDebug (const char *path, char const *argv[], char const *envp[], const char *stdio_path, nub_launch_flavor_t launch_flavor, DNBError &err);
+ static pid_t ForkChildForPTraceDebugging (const char *path, char const *argv[], char const *envp[], MachProcess* process, DNBError &err);
+ static pid_t PosixSpawnChildForPTraceDebugging (const char *path, char const *argv[], char const *envp[], const char *stdio_path, MachProcess* process, DNBError& err);
+ nub_addr_t GetDYLDAllImageInfosAddress ();
+ static const void * PrepareForAttach (const char *path, nub_launch_flavor_t launch_flavor, bool waitfor, DNBError &err_str);
+ static void CleanupAfterAttach (const void *attach_token, bool success, DNBError &err_str);
+ static nub_process_t CheckForProcess (const void *attach_token);
+#if defined (__arm__)
+ pid_t SBLaunchForDebug (const char *app_bundle_path, char const *argv[], char const *envp[], DNBError &launch_err);
+ static pid_t SBForkChildForPTraceDebugging (const char *path, char const *argv[], char const *envp[], MachProcess* process, DNBError &launch_err);
+#endif
+ nub_addr_t LookupSymbol (const char *name, const char *shlib);
+ void SetNameToAddressCallback (DNBCallbackNameToAddress callback, void *baton)
+ {
+ m_name_to_addr_callback = callback;
+ m_name_to_addr_baton = baton;
+ }
+ void SetSharedLibraryInfoCallback (DNBCallbackCopyExecutableImageInfos callback, void *baton)
+ {
+ m_image_infos_callback = callback;
+ m_image_infos_baton = baton;
+ }
+
+ bool Resume (const DNBThreadResumeActions& thread_actions);
+ bool Signal (int signal, const struct timespec *timeout_abstime = NULL);
+ bool Kill (const struct timespec *timeout_abstime = NULL);
+ bool Detach ();
+ nub_size_t ReadMemory (nub_addr_t addr, nub_size_t size, void *buf);
+ nub_size_t WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf);
+
+ //----------------------------------------------------------------------
+ // Path and arg accessors
+ //----------------------------------------------------------------------
+ const char * Path () const { return m_path.c_str(); }
+ size_t ArgumentCount () const { return m_args.size(); }
+ const char * ArgumentAtIndex (size_t arg_idx) const
+ {
+ if (arg_idx < m_args.size())
+ return m_args[arg_idx].c_str();
+ return NULL;
+ }
+
+ //----------------------------------------------------------------------
+ // Breakpoint functions
+ //----------------------------------------------------------------------
+ nub_break_t CreateBreakpoint (nub_addr_t addr, nub_size_t length, bool hardware, thread_t thread);
+ bool DisableBreakpoint (nub_break_t breakID, bool remove);
+ nub_size_t DisableAllBreakpoints (bool remove);
+ bool EnableBreakpoint (nub_break_t breakID);
+ void DumpBreakpoint(nub_break_t breakID) const;
+ DNBBreakpointList& Breakpoints() { return m_breakpoints; }
+ const DNBBreakpointList& Breakpoints() const { return m_breakpoints; }
+
+ //----------------------------------------------------------------------
+ // Watchpoint functions
+ //----------------------------------------------------------------------
+ nub_watch_t CreateWatchpoint (nub_addr_t addr, nub_size_t length, uint32_t watch_type, bool hardware, thread_t thread);
+ bool DisableWatchpoint (nub_watch_t watchID, bool remove);
+ nub_size_t DisableAllWatchpoints (bool remove);
+ bool EnableWatchpoint (nub_watch_t watchID);
+ void DumpWatchpoint(nub_watch_t watchID) const;
+ DNBBreakpointList& Watchpoints() { return m_watchpoints; }
+ const DNBBreakpointList& Watchpoints() const { return m_watchpoints; }
+
+ //----------------------------------------------------------------------
+ // Exception thread functions
+ //----------------------------------------------------------------------
+ bool StartSTDIOThread ();
+ static void * STDIOThread (void *arg);
+ void ExceptionMessageReceived (const MachException::Message& exceptionMessage);
+ void ExceptionMessageBundleComplete ();
+ void SharedLibrariesUpdated ();
+ nub_size_t CopyImageInfos (struct DNBExecutableImageInfo **image_infos, bool only_changed);
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ pid_t ProcessID () const { return m_pid; }
+ bool ProcessIDIsValid () const { return m_pid > 0; }
+ pid_t SetProcessID (pid_t pid);
+ MachTask& Task() { return m_task; }
+ const MachTask& Task() const { return m_task; }
+
+ PThreadEvent& Events() { return m_events; }
+ const DNBRegisterSetInfo *
+ GetRegisterSetInfo (nub_thread_t tid, nub_size_t *num_reg_sets) const;
+ bool GetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *reg_value) const;
+ bool SetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value) const;
+ const char * ThreadGetName (nub_thread_t tid);
+ nub_state_t ThreadGetState (nub_thread_t tid);
+ nub_size_t GetNumThreads () const;
+ nub_thread_t GetThreadAtIndex (nub_size_t thread_idx) const;
+ uint32_t GetThreadIndexFromThreadID (nub_thread_t tid);
+ nub_thread_t GetCurrentThread ();
+ nub_thread_t SetCurrentThread (nub_thread_t tid);
+ MachThreadList & GetThreadList() { return m_threadList; }
+ bool GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const;
+ void DumpThreadStoppedReason(nub_thread_t tid) const;
+ const char * GetThreadInfo (nub_thread_t tid) const;
+
+ nub_state_t GetState ();
+ void SetState (nub_state_t state);
+ bool IsRunning (nub_state_t state)
+ {
+ return state == eStateRunning || IsStepping(state);
+ }
+ bool IsStepping (nub_state_t state)
+ {
+ return state == eStateStepping;
+ }
+ bool CanResume (nub_state_t state)
+ {
+ return state == eStateStopped;
+ }
+
+ const DNBError& GetLastError () const { return m_err; }
+
+ bool GetExitStatus(int* status)
+ {
+ if (GetState() == eStateExited)
+ {
+ if (status)
+ *status = m_exit_status;
+ return true;
+ }
+ return false;
+ }
+ void SetExitStatus(int status)
+ {
+ m_exit_status = status;
+ SetState(eStateExited);
+ }
+
+ uint32_t StopCount() const { return m_stop_count; }
+ void SetChildFileDescriptors (int stdin_fileno, int stdout_fileno, int stderr_fileno)
+ {
+ m_child_stdin = stdin_fileno;
+ m_child_stdout = stdout_fileno;
+ m_child_stderr = stderr_fileno;
+ }
+
+ int GetStdinFileDescriptor () const { return m_child_stdin; }
+ int GetStdoutFileDescriptor () const { return m_child_stdout; }
+ int GetStderrFileDescriptor () const { return m_child_stderr; }
+ void AppendSTDOUT (char* s, size_t len);
+ size_t GetAvailableSTDOUT (char *buf, size_t buf_size);
+ size_t GetAvailableSTDERR (char *buf, size_t buf_size);
+ void CloseChildFileDescriptors ()
+ {
+ if (m_child_stdin >= 0)
+ {
+ ::close (m_child_stdin);
+ m_child_stdin = -1;
+ }
+ if (m_child_stdout >= 0)
+ {
+ ::close (m_child_stdout);
+ m_child_stdout = -1;
+ }
+ if (m_child_stderr >= 0)
+ {
+ ::close (m_child_stderr);
+ m_child_stderr = -1;
+ }
+ }
+
+ bool ProcessUsingSpringBoard() const { return (m_flags & eMachProcessFlagsUsingSBS) != 0; }
+private:
+ enum
+ {
+ eMachProcessFlagsNone = 0,
+ eMachProcessFlagsAttached = (1 << 0),
+ eMachProcessFlagsUsingSBS = (1 << 1)
+ };
+ void Clear ();
+ void ReplyToAllExceptions (const DNBThreadResumeActions& thread_actions);
+ void PrivateResume (const DNBThreadResumeActions& thread_actions);
+ nub_size_t RemoveTrapsFromBuffer (nub_addr_t addr, nub_size_t size, uint8_t *buf) const;
+
+ uint32_t Flags () const { return m_flags; }
+ nub_state_t DoSIGSTOP (bool clear_bps_and_wps);
+
+ pid_t m_pid; // Process ID of child process
+ int m_child_stdin;
+ int m_child_stdout;
+ int m_child_stderr;
+ std::string m_path; // A path to the executable if we have one
+ std::vector<std::string> m_args; // The arguments with which the process was lauched
+ int m_exit_status; // The exit status for the process
+ MachTask m_task; // The mach task for this process
+ uint32_t m_flags; // Process specific flags (see eMachProcessFlags enums)
+ uint32_t m_stop_count; // A count of many times have we stopped
+ pthread_t m_stdio_thread; // Thread ID for the thread that watches for child process stdio
+ PThreadMutex m_stdio_mutex; // Multithreaded protection for stdio
+ std::string m_stdout_data;
+ MachException::Message::collection
+ m_exception_messages; // A collection of exception messages caught when listening to the exception port
+ PThreadMutex m_exception_messages_mutex; // Multithreaded protection for m_exception_messages
+
+ MachThreadList m_threadList; // A list of threads that is maintained/updated after each stop
+ DNBError m_err; // The last error for any transaction
+ nub_state_t m_state; // The state of our process
+ PThreadMutex m_state_mutex; // Multithreaded protection for m_state
+ PThreadEvent m_events; // Process related events in the child processes lifetime can be waited upon
+ DNBBreakpointList m_breakpoints; // Breakpoint list for this process
+ DNBBreakpointList m_watchpoints; // Watchpoint list for this process
+ DNBCallbackNameToAddress m_name_to_addr_callback;
+ void * m_name_to_addr_baton;
+ DNBCallbackCopyExecutableImageInfos
+ m_image_infos_callback;
+ void * m_image_infos_baton;
+};
+
+
+#endif // __MachProcess_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/MachTask.cpp b/lldb/tools/debugserver/source/MacOSX/MachTask.cpp
new file mode 100644
index 00000000000..68d858c014c
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachTask.cpp
@@ -0,0 +1,660 @@
+//===-- MachTask.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// MachTask.cpp
+// debugserver
+//
+// Created by Greg Clayton on 12/5/08.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachTask.h"
+
+// C Includes
+
+#include <mach-o/dyld_images.h>
+#include <mach/mach_vm.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "CFUtils.h"
+#include "DNB.h"
+#include "DNBError.h"
+#include "DNBLog.h"
+#include "MachProcess.h"
+#include "DNBDataRef.h"
+
+#if defined (__arm__)
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <SpringBoardServices/SpringBoardServer.h>
+#include <SpringBoardServices/SBSWatchdogAssertion.h>
+
+#endif
+
+//----------------------------------------------------------------------
+// MachTask constructor
+//----------------------------------------------------------------------
+MachTask::MachTask(MachProcess *process) :
+ m_process (process),
+ m_task (TASK_NULL),
+ m_vm_memory (),
+ m_exception_thread (0),
+ m_exception_port (MACH_PORT_NULL)
+{
+ memset(&m_exc_port_info, 0, sizeof(m_exc_port_info));
+
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+MachTask::~MachTask()
+{
+ Clear();
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::Suspend
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::Suspend()
+{
+ DNBError err;
+ task_t task = TaskPort();
+ err = ::task_suspend (task);
+ if (DNBLogCheckLogBit(LOG_TASK) || err.Fail())
+ err.LogThreaded("::task_suspend ( target_task = 0x%4.4x )", task);
+ return err.Error();
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::Resume
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::Resume()
+{
+ struct task_basic_info task_info;
+ task_t task = TaskPort();
+
+ DNBError err;
+ err = BasicInfo(task, &task_info);
+
+ if (err.Success())
+ {
+ integer_t i;
+ for (i=0; i<task_info.suspend_count; i++)
+ {
+ err = ::task_resume (task);
+ if (DNBLogCheckLogBit(LOG_TASK) || err.Fail())
+ err.LogThreaded("::task_resume ( target_task = 0x%4.4x )", task);
+ }
+ }
+ return err.Error();
+}
+
+//----------------------------------------------------------------------
+// MachTask::ExceptionPort
+//----------------------------------------------------------------------
+mach_port_t
+MachTask::ExceptionPort() const
+{
+ return m_exception_port;
+}
+
+//----------------------------------------------------------------------
+// MachTask::ExceptionPortIsValid
+//----------------------------------------------------------------------
+bool
+MachTask::ExceptionPortIsValid() const
+{
+ return MACH_PORT_VALID(m_exception_port);
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::Clear
+//----------------------------------------------------------------------
+void
+MachTask::Clear()
+{
+ // Do any cleanup needed for this task
+ m_task = TASK_NULL;
+ m_exception_thread = 0;
+ m_exception_port = MACH_PORT_NULL;
+
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::SaveExceptionPortInfo
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::SaveExceptionPortInfo()
+{
+ return m_exc_port_info.Save(TaskPort());
+}
+
+//----------------------------------------------------------------------
+// MachTask::RestoreExceptionPortInfo
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::RestoreExceptionPortInfo()
+{
+ return m_exc_port_info.Restore(TaskPort());
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::ReadMemory
+//----------------------------------------------------------------------
+nub_size_t
+MachTask::ReadMemory (nub_addr_t addr, nub_size_t size, void *buf)
+{
+ nub_size_t n = 0;
+ task_t task = TaskPort();
+ if (task != TASK_NULL)
+ {
+ n = m_vm_memory.Read(task, addr, buf, size);
+
+ DNBLogThreadedIf(LOG_MEMORY, "MachTask::ReadMemory ( addr = 0x%8.8llx, size = %zu, buf = %8.8p) => %u bytes read", (uint64_t)addr, size, buf, n);
+ if (DNBLogCheckLogBit(LOG_MEMORY_DATA_LONG) || (DNBLogCheckLogBit(LOG_MEMORY_DATA_SHORT) && size <= 8))
+ {
+ DNBDataRef data((uint8_t*)buf, n, false);
+ data.Dump(0, n, addr, DNBDataRef::TypeUInt8, 16);
+ }
+ }
+ return n;
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::WriteMemory
+//----------------------------------------------------------------------
+nub_size_t
+MachTask::WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf)
+{
+ nub_size_t n = 0;
+ task_t task = TaskPort();
+ if (task != TASK_NULL)
+ {
+ n = m_vm_memory.Write(task, addr, buf, size);
+ DNBLogThreadedIf(LOG_MEMORY, "MachTask::WriteMemory ( addr = 0x%8.8llx, size = %zu, buf = %8.8p) => %u bytes written", (uint64_t)addr, size, buf, n);
+ if (DNBLogCheckLogBit(LOG_MEMORY_DATA_LONG) || (DNBLogCheckLogBit(LOG_MEMORY_DATA_SHORT) && size <= 8))
+ {
+ DNBDataRef data((uint8_t*)buf, n, false);
+ data.Dump(0, n, addr, DNBDataRef::TypeUInt8, 16);
+ }
+ }
+ return n;
+}
+
+//----------------------------------------------------------------------
+// MachTask::TaskPortForProcessID
+//----------------------------------------------------------------------
+task_t
+MachTask::TaskPortForProcessID (DNBError &err)
+{
+ if (m_task == TASK_NULL && m_process != NULL)
+ m_task = MachTask::TaskPortForProcessID(m_process->ProcessID(), err);
+ return m_task;
+}
+
+//----------------------------------------------------------------------
+// MachTask::TaskPortForProcessID
+//----------------------------------------------------------------------
+task_t
+MachTask::TaskPortForProcessID (pid_t pid, DNBError &err)
+{
+ task_t task = TASK_NULL;
+ if (pid != INVALID_NUB_PROCESS)
+ {
+ mach_port_t task_self = mach_task_self ();
+ err = ::task_for_pid ( task_self, pid, &task);
+ if (DNBLogCheckLogBit(LOG_TASK) || err.Fail())
+ {
+ char str[1024];
+ ::snprintf (str,
+ sizeof(str),
+ "::task_for_pid ( task_self, pid = %d, task => TASK_NULL (0x%4.4x) ) uid=%u, euid=%u gid=%u egid=%u (%s)",
+ pid,
+ task,
+ getuid(),
+ geteuid(),
+ getgid(),
+ getegid(),
+ err.AsString() ? err.AsString() : "success");
+ if (err.Fail())
+ err.SetErrorString(str);
+ err.LogThreaded(str);
+ }
+ }
+ return task;
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::BasicInfo
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::BasicInfo(struct task_basic_info *info)
+{
+ return BasicInfo (TaskPort(), info);
+}
+
+//----------------------------------------------------------------------
+// MachTask::BasicInfo
+//----------------------------------------------------------------------
+kern_return_t
+MachTask::BasicInfo(task_t task, struct task_basic_info *info)
+{
+ if (info == NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ DNBError err;
+ mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
+ err = ::task_info (task, TASK_BASIC_INFO, (task_info_t)info, &count);
+ const bool log_process = DNBLogCheckLogBit(LOG_TASK);
+ if (log_process || err.Fail())
+ err.LogThreaded("::task_info ( target_task = 0x%4.4x, flavor = TASK_BASIC_INFO, task_info_out => %p, task_info_outCnt => %u )", task, info, count);
+ if (DNBLogCheckLogBit(LOG_TASK) && DNBLogCheckLogBit(LOG_VERBOSE) && err.Success())
+ {
+ float user = (float)info->user_time.seconds + (float)info->user_time.microseconds / 1000000.0f;
+ float system = (float)info->user_time.seconds + (float)info->user_time.microseconds / 1000000.0f;
+ DNBLogThreaded("task_basic_info = { suspend_count = %i, virtual_size = 0x%8.8x, resident_size = 0x%8.8x, user_time = %f, system_time = %f }",
+ info->suspend_count, info->virtual_size, info->resident_size, user, system);
+ }
+ return err.Error();
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::IsValid
+//
+// Returns true if a task is a valid task port for a current process.
+//----------------------------------------------------------------------
+bool
+MachTask::IsValid () const
+{
+ return MachTask::IsValid(TaskPort());
+}
+
+//----------------------------------------------------------------------
+// MachTask::IsValid
+//
+// Returns true if a task is a valid task port for a current process.
+//----------------------------------------------------------------------
+bool
+MachTask::IsValid (task_t task)
+{
+ if (task != TASK_NULL)
+ {
+ struct task_basic_info task_info;
+ return BasicInfo(task, &task_info) == KERN_SUCCESS;
+ }
+ return false;
+}
+
+
+bool
+MachTask::StartExceptionThread(DNBError &err)
+{
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s ( )", __FUNCTION__);
+ task_t task = TaskPortForProcessID(err);
+ if (MachTask::IsValid(task))
+ {
+ // Got the mach port for the current process
+ mach_port_t task_self = mach_task_self ();
+
+ // Allocate an exception port that we will use to track our child process
+ err = ::mach_port_allocate (task_self, MACH_PORT_RIGHT_RECEIVE, &m_exception_port);
+ if (err.Fail())
+ return false;
+
+ // Add the ability to send messages on the new exception port
+ err = ::mach_port_insert_right (task_self, m_exception_port, m_exception_port, MACH_MSG_TYPE_MAKE_SEND);
+ if (err.Fail())
+ return false;
+
+ // Save the original state of the exception ports for our child process
+ SaveExceptionPortInfo();
+
+ // Set the ability to get all exceptions on this port
+ err = ::task_set_exception_ports (task, EXC_MASK_ALL, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
+ if (err.Fail())
+ return false;
+
+ // Create the exception thread
+ err = ::pthread_create (&m_exception_thread, NULL, MachTask::ExceptionThread, this);
+ return err.Success();
+ }
+ else
+ {
+ DNBLogError("MachTask::%s (): task invalid, exception thread start failed.", __FUNCTION__);
+ }
+ return false;
+}
+
+kern_return_t
+MachTask::ShutDownExcecptionThread()
+{
+ DNBError err;
+
+ err = RestoreExceptionPortInfo();
+
+ // NULL our our exception port and let our exception thread exit
+ mach_port_t exception_port = m_exception_port;
+ m_exception_port = NULL;
+
+ err.SetError(::pthread_cancel(m_exception_thread), DNBError::POSIX);
+ if (DNBLogCheckLogBit(LOG_TASK) || err.Fail())
+ err.LogThreaded("::pthread_cancel ( thread = %p )", m_exception_thread);
+
+ err.SetError(::pthread_join(m_exception_thread, NULL), DNBError::POSIX);
+ if (DNBLogCheckLogBit(LOG_TASK) || err.Fail())
+ err.LogThreaded("::pthread_join ( thread = %p, value_ptr = NULL)", m_exception_thread);
+
+ // Deallocate our exception port that we used to track our child process
+ mach_port_t task_self = mach_task_self ();
+ err = ::mach_port_deallocate (task_self, exception_port);
+ if (DNBLogCheckLogBit(LOG_TASK) || err.Fail())
+ err.LogThreaded("::mach_port_deallocate ( task = 0x%4.4x, name = 0x%4.4x )", task_self, exception_port);
+ exception_port = NULL;
+
+ return err.Error();
+}
+
+
+void *
+MachTask::ExceptionThread (void *arg)
+{
+ if (arg == NULL)
+ return NULL;
+
+ MachTask *mach_task = (MachTask*) arg;
+ MachProcess *mach_proc = mach_task->Process();
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s ( arg = %p ) starting thread...", __FUNCTION__, arg);
+
+ // We keep a count of the number of consecutive exceptions received so
+ // we know to grab all exceptions without a timeout. We do this to get a
+ // bunch of related exceptions on our exception port so we can process
+ // then together. When we have multiple threads, we can get an exception
+ // per thread and they will come in consecutively. The main loop in this
+ // thread can stop periodically if needed to service things related to this
+ // process.
+ // flag set in the options, so we will wait forever for an exception on
+ // our exception port. After we get one exception, we then will use the
+ // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current
+ // exceptions for our process. After we have received the last pending
+ // exception, we will get a timeout which enables us to then notify
+ // our main thread that we have an exception bundle avaiable. We then wait
+ // for the main thread to tell this exception thread to start trying to get
+ // exceptions messages again and we start again with a mach_msg read with
+ // infinite timeout.
+ uint32_t num_exceptions_received = 0;
+ DNBError err;
+ task_t task = mach_task->TaskPort();
+ mach_msg_timeout_t periodic_timeout = 0;
+
+#if defined (__arm__)
+ mach_msg_timeout_t watchdog_elapsed = 0;
+ mach_msg_timeout_t watchdog_timeout = 60 * 1000;
+ pid_t pid = mach_proc->ProcessID();
+ CFReleaser<SBSWatchdogAssertionRef> watchdog;
+
+ if (mach_proc->ProcessUsingSpringBoard())
+ {
+ // Request a renewal for every 60 seconds if we attached using SpringBoard
+ watchdog.reset(::SBSWatchdogAssertionCreateForPID(NULL, pid, 60));
+ DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionCreateForPID (NULL, %4.4x, 60 ) => %p", pid, watchdog.get());
+
+ if (watchdog.get())
+ {
+ ::SBSWatchdogAssertionRenew (watchdog.get());
+
+ CFTimeInterval watchdogRenewalInterval = ::SBSWatchdogAssertionGetRenewalInterval (watchdog.get());
+ DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionGetRenewalInterval ( %p ) => %g seconds", watchdog.get(), watchdogRenewalInterval);
+ if (watchdogRenewalInterval > 0.0)
+ {
+ watchdog_timeout = (mach_msg_timeout_t)watchdogRenewalInterval * 1000;
+ if (watchdog_timeout > 3000)
+ watchdog_timeout -= 1000; // Give us a second to renew our timeout
+ else if (watchdog_timeout > 1000)
+ watchdog_timeout -= 250; // Give us a quarter of a second to renew our timeout
+ }
+ }
+ if (periodic_timeout == 0 || periodic_timeout > watchdog_timeout)
+ periodic_timeout = watchdog_timeout;
+ }
+#endif // #if defined (__arm__)
+
+ while (mach_task->ExceptionPortIsValid())
+ {
+ ::pthread_testcancel ();
+
+ MachException::Message exception_message;
+
+
+ if (num_exceptions_received > 0)
+ {
+ // No timeout, just receive as many exceptions as we can since we already have one and we want
+ // to get all currently available exceptions for this task
+ err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, 0);
+ }
+ else if (periodic_timeout > 0)
+ {
+ // We need to stop periodically in this loop, so try and get a mach message with a valid timeout (ms)
+ err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, periodic_timeout);
+ }
+ else
+ {
+ // We don't need to parse all current exceptions or stop periodically,
+ // just wait for an exception forever.
+ err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0);
+ }
+
+ if (err.Error() == MACH_RCV_INTERRUPTED)
+ {
+ // If we have no task port we should exit this thread
+ if (!mach_task->ExceptionPortIsValid())
+ {
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "thread cancelled...");
+ break;
+ }
+
+ // Make sure our task is still valid
+ if (MachTask::IsValid(task))
+ {
+ // Task is still ok
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "interrupted, but task still valid, continuing...");
+ continue;
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "task has exited...");
+ mach_proc->SetState(eStateExited);
+ // Our task has died, exit the thread.
+ break;
+ }
+ }
+ else if (err.Error() == MACH_RCV_TIMED_OUT)
+ {
+ if (num_exceptions_received > 0)
+ {
+ // We were receiving all current exceptions with a timeout of zero
+ // it is time to go back to our normal looping mode
+ num_exceptions_received = 0;
+
+ // Notify our main thread we have a complete exception message
+ // bundle available.
+ mach_proc->ExceptionMessageBundleComplete();
+
+ // in case we use a timeout value when getting exceptions...
+ // Make sure our task is still valid
+ if (MachTask::IsValid(task))
+ {
+ // Task is still ok
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "got a timeout, continuing...");
+ continue;
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "task has exited...");
+ mach_proc->SetState(eStateExited);
+ // Our task has died, exit the thread.
+ break;
+ }
+ continue;
+ }
+
+#if defined (__arm__)
+ if (watchdog.get())
+ {
+ watchdog_elapsed += periodic_timeout;
+ if (watchdog_elapsed >= watchdog_timeout)
+ {
+ DNBLogThreadedIf(LOG_TASK, "SBSWatchdogAssertionRenew ( %p )", watchdog.get());
+ ::SBSWatchdogAssertionRenew (watchdog.get());
+ watchdog_elapsed = 0;
+ }
+ }
+#endif
+ }
+ else if (err.Error() != KERN_SUCCESS)
+ {
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "got some other error, do something about it??? nah, continuing for now...");
+ // TODO: notify of error?
+ }
+ else
+ {
+ if (exception_message.CatchExceptionRaise())
+ {
+ ++num_exceptions_received;
+ mach_proc->ExceptionMessageReceived(exception_message);
+ }
+ }
+ }
+
+#if defined (__arm__)
+ if (watchdog.get())
+ {
+ // TODO: change SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel when we
+ // all are up and running on systems that support it. The SBS framework has a #define
+ // that will forward SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel for now
+ // so it should still build either way.
+ DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionRelease(%p)", watchdog.get());
+ ::SBSWatchdogAssertionRelease (watchdog.get());
+ }
+#endif // #if defined (__arm__)
+
+ DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s (%p): thread exiting...", __FUNCTION__, arg);
+ return NULL;
+}
+
+
+// So the TASK_DYLD_INFO used to just return the address of the all image infos
+// as a single member called "all_image_info". Then someone decided it would be
+// a good idea to rename this first member to "all_image_info_addr" and add a
+// size member called "all_image_info_size". This of course can not be detected
+// using code or #defines. So to hack around this problem, we define our own
+// version of the TASK_DYLD_INFO structure so we can guarantee what is inside it.
+
+struct hack_task_dyld_info {
+ mach_vm_address_t all_image_info_addr;
+ mach_vm_size_t all_image_info_size;
+};
+
+nub_addr_t
+MachTask::GetDYLDAllImageInfosAddress (DNBError& err)
+{
+ struct hack_task_dyld_info dyld_info;
+ mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+ // Make sure that COUNT isn't bigger than our hacked up struct hack_task_dyld_info.
+ // If it is, then make COUNT smaller to match.
+ if (count > (sizeof(struct hack_task_dyld_info) / sizeof(natural_t)))
+ count = (sizeof(struct hack_task_dyld_info) / sizeof(natural_t));
+
+ task_t task = TaskPortForProcessID (err);
+ if (err.Success())
+ {
+ err = ::task_info (task, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
+ if (err.Success())
+ {
+ // We now have the address of the all image infos structure
+ return dyld_info.all_image_info_addr;
+ }
+ }
+ return INVALID_NUB_ADDRESS;
+}
+
+
+//----------------------------------------------------------------------
+// MachTask::AllocateMemory
+//----------------------------------------------------------------------
+nub_addr_t
+MachTask::AllocateMemory (size_t size, uint32_t permissions)
+{
+ mach_vm_address_t addr;
+ task_t task = TaskPort();
+ if (task == TASK_NULL)
+ return INVALID_NUB_ADDRESS;
+
+ DNBError err;
+ err = ::mach_vm_allocate (task, &addr, size, TRUE);
+ if (err.Error() == KERN_SUCCESS)
+ {
+ // Set the protections:
+ vm_prot_t mach_prot = 0;
+ if (permissions & eMemoryPermissionsReadable)
+ mach_prot |= VM_PROT_READ;
+ if (permissions & eMemoryPermissionsWritable)
+ mach_prot |= VM_PROT_WRITE;
+ if (permissions & eMemoryPermissionsExecutable)
+ mach_prot |= VM_PROT_EXECUTE;
+
+
+ err = ::mach_vm_protect (task, addr, size, 0, mach_prot);
+ if (err.Error() == KERN_SUCCESS)
+ {
+ m_allocations.insert (std::make_pair(addr, size));
+ return addr;
+ }
+ ::mach_vm_deallocate (task, addr, size);
+ }
+ return INVALID_NUB_ADDRESS;
+}
+
+//----------------------------------------------------------------------
+// MachTask::DeallocateMemory
+//----------------------------------------------------------------------
+nub_bool_t
+MachTask::DeallocateMemory (nub_addr_t addr)
+{
+ task_t task = TaskPort();
+ if (task == TASK_NULL)
+ return false;
+
+ // We have to stash away sizes for the allocations...
+ allocation_collection::iterator pos, end = m_allocations.end();
+ for (pos = m_allocations.begin(); pos != end; pos++)
+ {
+ if ((*pos).first == addr)
+ {
+ m_allocations.erase(pos);
+ return ::mach_vm_deallocate (task, (*pos).first, (*pos).second) == KERN_SUCCESS;
+ }
+
+ }
+ return false;
+}
+
diff --git a/lldb/tools/debugserver/source/MacOSX/MachTask.h b/lldb/tools/debugserver/source/MacOSX/MachTask.h
new file mode 100644
index 00000000000..3bf40e13457
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachTask.h
@@ -0,0 +1,91 @@
+//===-- MachTask.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// MachTask.h
+// debugserver
+//
+// Created by Greg Clayton on 12/5/08.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __MachTask_h__
+#define __MachTask_h__
+
+// C Includes
+#include <mach/mach.h>
+#include <sys/socket.h>
+// C++ Includes
+#include <map>
+// Other libraries and framework includes
+// Project includes
+#include "MachException.h"
+#include "MachVMMemory.h"
+#include "PThreadMutex.h"
+
+class MachProcess;
+
+class MachTask
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ MachTask (MachProcess *process);
+ virtual ~MachTask ();
+
+ void Clear ();
+
+ kern_return_t Suspend ();
+ kern_return_t Resume ();
+
+ nub_size_t ReadMemory (nub_addr_t addr, nub_size_t size, void *buf);
+ nub_size_t WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf);
+
+ nub_addr_t AllocateMemory (nub_size_t size, uint32_t permissions);
+ nub_bool_t DeallocateMemory (nub_addr_t addr);
+
+ mach_port_t ExceptionPort () const;
+ bool ExceptionPortIsValid () const;
+ kern_return_t SaveExceptionPortInfo ();
+ kern_return_t RestoreExceptionPortInfo ();
+ kern_return_t ShutDownExcecptionThread ();
+
+ bool StartExceptionThread (DNBError &err);
+ nub_addr_t GetDYLDAllImageInfosAddress (DNBError& err);
+ kern_return_t BasicInfo (struct task_basic_info *info);
+ static kern_return_t BasicInfo (task_t task, struct task_basic_info *info);
+ bool IsValid () const;
+ static bool IsValid (task_t task);
+ static void * ExceptionThread (void *arg);
+ task_t TaskPort () const { return m_task; }
+ task_t TaskPortForProcessID (DNBError &err);
+ static task_t TaskPortForProcessID (pid_t pid, DNBError &err);
+
+ MachProcess * Process () { return m_process; }
+ const MachProcess * Process () const { return m_process; }
+
+protected:
+ MachProcess * m_process; // The mach process that owns this MachTask
+ task_t m_task;
+ MachVMMemory m_vm_memory; // Special mach memory reading class that will take care of watching for page and region boundaries
+ MachException::PortInfo
+ m_exc_port_info; // Saved settings for all exception ports
+ pthread_t m_exception_thread; // Thread ID for the exception thread in case we need it
+ mach_port_t m_exception_port; // Exception port on which we will receive child exceptions
+
+ typedef std::map <mach_vm_address_t, size_t> allocation_collection;
+ allocation_collection m_allocations;
+
+private:
+ MachTask(const MachTask&); // Outlaw
+ MachTask& operator=(const MachTask& rhs);// Outlaw
+};
+
+#endif // __MachTask_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp
new file mode 100644
index 00000000000..9d018f66ea6
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp
@@ -0,0 +1,745 @@
+//===-- MachThread.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/19/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachThread.h"
+#include "MachProcess.h"
+#include "DNBLog.h"
+#include "DNB.h"
+
+static uint32_t
+GetSequenceID()
+{
+ static uint32_t g_nextID = 0;
+ return ++g_nextID;
+}
+
+MachThread::MachThread (MachProcess *process, thread_t thread) :
+ m_process(process),
+ m_tid(thread),
+ m_seq_id(GetSequenceID()),
+ m_state(eStateUnloaded),
+ m_state_mutex(PTHREAD_MUTEX_RECURSIVE),
+ m_breakID(INVALID_NUB_BREAK_ID),
+ m_suspendCount(0),
+ m_arch(this),
+ m_regSets()
+{
+ nub_size_t num_reg_sets = 0;
+ const DNBRegisterSetInfo *regSetInfo = m_arch.GetRegisterSetInfo(&num_reg_sets);
+ if (num_reg_sets > 0)
+ m_regSets.assign(regSetInfo, regSetInfo + num_reg_sets);
+
+ ::memset (&m_basicInfo, 0, sizeof (m_basicInfo));
+ DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::MachThread ( process = %p, tid = 0x%4.4x, seq_id = %u )", &m_process, m_tid, m_seq_id);
+}
+
+MachThread::~MachThread()
+{
+ DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::~MachThread() for tid = 0x%4.4x (%u)", m_tid, m_seq_id);
+}
+
+
+
+uint32_t
+MachThread::Suspend()
+{
+ DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
+ if (ThreadIDIsValid(m_tid))
+ {
+ DNBError err(::thread_suspend (m_tid), DNBError::MachKernel);
+ if (err.Success())
+ m_suspendCount++;
+ if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
+ err.LogThreaded("::thread_suspend (%4.4x)", m_tid);
+ }
+ return SuspendCount();
+}
+
+uint32_t
+MachThread::Resume()
+{
+ DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
+ if (ThreadIDIsValid(m_tid))
+ {
+ while (m_suspendCount > 0)
+ {
+ DNBError err(::thread_resume (m_tid), DNBError::MachKernel);
+ if (err.Success())
+ m_suspendCount--;
+ if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
+ err.LogThreaded("::thread_resume (%4.4x)", m_tid);
+ }
+ }
+ return SuspendCount();
+}
+
+bool
+MachThread::RestoreSuspendCount()
+{
+ DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
+ DNBError err;
+ if (ThreadIDIsValid(m_tid) == false)
+ return false;
+ else if (m_suspendCount > m_basicInfo.suspend_count)
+ {
+ while (m_suspendCount > m_basicInfo.suspend_count)
+ {
+ err = ::thread_resume (m_tid);
+ if (err.Success())
+ --m_suspendCount;
+ if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
+ err.LogThreaded("::thread_resume (%4.4x)", m_tid);
+ }
+ }
+ else if (m_suspendCount < m_basicInfo.suspend_count)
+ {
+ while (m_suspendCount < m_basicInfo.suspend_count)
+ {
+ err = ::thread_suspend (m_tid);
+ if (err.Success())
+ --m_suspendCount;
+ if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
+ err.LogThreaded("::thread_suspend (%4.4x)", m_tid);
+ }
+ }
+ return m_suspendCount == m_basicInfo.suspend_count;
+}
+
+
+const char *
+MachThread::GetBasicInfoAsString () const
+{
+ static char g_basic_info_string[1024];
+ struct thread_basic_info basicInfo;
+
+ if (GetBasicInfo(m_tid, &basicInfo))
+ {
+
+// char run_state_str[32];
+// size_t run_state_str_size = sizeof(run_state_str);
+// switch (basicInfo.run_state)
+// {
+// case TH_STATE_RUNNING: strncpy(run_state_str, "running", run_state_str_size); break;
+// case TH_STATE_STOPPED: strncpy(run_state_str, "stopped", run_state_str_size); break;
+// case TH_STATE_WAITING: strncpy(run_state_str, "waiting", run_state_str_size); break;
+// case TH_STATE_UNINTERRUPTIBLE: strncpy(run_state_str, "uninterruptible", run_state_str_size); break;
+// case TH_STATE_HALTED: strncpy(run_state_str, "halted", run_state_str_size); break;
+// default: snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break; // ???
+// }
+ float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
+ float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
+ snprintf(g_basic_info_string, sizeof(g_basic_info_string), "Thread 0x%4.4x: user=%f system=%f cpu=%d sleep_time=%d",
+ InferiorThreadID(),
+ user,
+ system,
+ basicInfo.cpu_usage,
+ basicInfo.sleep_time);
+
+ return g_basic_info_string;
+ }
+ return NULL;
+}
+
+thread_t
+MachThread::InferiorThreadID() const
+{
+ mach_msg_type_number_t i;
+ mach_port_name_array_t names;
+ mach_port_type_array_t types;
+ mach_msg_type_number_t ncount, tcount;
+ thread_t inferior_tid = INVALID_NUB_THREAD;
+ task_t my_task = ::mach_task_self();
+ task_t task = m_process->Task().TaskPort();
+
+ kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount);
+ if (kret == KERN_SUCCESS)
+ {
+
+ for (i = 0; i < ncount; i++)
+ {
+ mach_port_t my_name;
+ mach_msg_type_name_t my_type;
+
+ kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type);
+ if (kret == KERN_SUCCESS)
+ {
+ ::mach_port_deallocate (my_task, my_name);
+ if (my_name == m_tid)
+ {
+ inferior_tid = names[i];
+ break;
+ }
+ }
+ }
+ // Free up the names and types
+ ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t));
+ ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t));
+ }
+ return inferior_tid;
+}
+
+bool
+MachThread::GetBasicInfo(thread_t thread, struct thread_basic_info *basicInfoPtr)
+{
+ if (ThreadIDIsValid(thread))
+ {
+ unsigned int info_count = THREAD_BASIC_INFO_COUNT;
+ kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count);
+ if (err == KERN_SUCCESS)
+ return true;
+ }
+ ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info));
+ return false;
+}
+
+
+bool
+MachThread::ThreadIDIsValid(thread_t thread)
+{
+ return thread != THREAD_NULL;
+}
+
+bool
+MachThread::GetRegisterState(int flavor, bool force)
+{
+ return m_arch.GetRegisterState(flavor, force) == KERN_SUCCESS;
+}
+
+bool
+MachThread::SetRegisterState(int flavor)
+{
+ return m_arch.SetRegisterState(flavor) == KERN_SUCCESS;
+}
+
+uint64_t
+MachThread::GetPC(uint64_t failValue)
+{
+ // Get program counter
+ return m_arch.GetPC(failValue);
+}
+
+bool
+MachThread::SetPC(uint64_t value)
+{
+ // Set program counter
+ return m_arch.SetPC(value);
+}
+
+uint64_t
+MachThread::GetSP(uint64_t failValue)
+{
+ // Get stack pointer
+ return m_arch.GetSP(failValue);
+}
+
+nub_process_t
+MachThread::ProcessID() const
+{
+ if (m_process)
+ return m_process->ProcessID();
+ return INVALID_NUB_PROCESS;
+}
+
+void
+MachThread::Dump(uint32_t index)
+{
+ const char * thread_run_state = NULL;
+
+ switch (m_basicInfo.run_state)
+ {
+ case TH_STATE_RUNNING: thread_run_state = "running"; break; // 1 thread is running normally
+ case TH_STATE_STOPPED: thread_run_state = "stopped"; break; // 2 thread is stopped
+ case TH_STATE_WAITING: thread_run_state = "waiting"; break; // 3 thread is waiting normally
+ case TH_STATE_UNINTERRUPTIBLE: thread_run_state = "uninter"; break; // 4 thread is in an uninterruptible wait
+ case TH_STATE_HALTED: thread_run_state = "halted "; break; // 5 thread is halted at a
+ default: thread_run_state = "???"; break;
+ }
+
+ DNBLogThreaded("thread[%u] %4.4x (%u): pc: 0x%8.8llx sp: 0x%8.8llx breakID: %d user: %d.%06.6d system: %d.%06.6d cpu: %d policy: %d run_state: %d (%s) flags: %d suspend_count: %d (current %d) sleep_time: %d",
+ index,
+ m_tid,
+ m_seq_id,
+ GetPC(INVALID_NUB_ADDRESS),
+ GetSP(INVALID_NUB_ADDRESS),
+ m_breakID,
+ m_basicInfo.user_time.seconds, m_basicInfo.user_time.microseconds,
+ m_basicInfo.system_time.seconds, m_basicInfo.system_time.microseconds,
+ m_basicInfo.cpu_usage,
+ m_basicInfo.policy,
+ m_basicInfo.run_state,
+ thread_run_state,
+ m_basicInfo.flags,
+ m_basicInfo.suspend_count, m_suspendCount,
+ m_basicInfo.sleep_time);
+ //DumpRegisterState(0);
+}
+
+void
+MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action)
+{
+ if (thread_action->addr != INVALID_NUB_ADDRESS)
+ SetPC (thread_action->addr);
+
+ SetState (thread_action->state);
+ switch (thread_action->state)
+ {
+ case eStateStopped:
+ case eStateSuspended:
+ Suspend();
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ Resume();
+ break;
+ }
+ m_arch.ThreadWillResume();
+ m_stop_exception.Clear();
+}
+
+bool
+MachThread::ShouldStop(bool &step_more)
+{
+ // See if this thread is at a breakpoint?
+ nub_break_t breakID = CurrentBreakpoint();
+
+ if (NUB_BREAK_ID_IS_VALID(breakID))
+ {
+ // This thread is sitting at a breakpoint, ask the breakpoint
+ // if we should be stopping here.
+ if (Process()->Breakpoints().ShouldStop(ProcessID(), ThreadID(), breakID))
+ return true;
+ else
+ {
+ // The breakpoint said we shouldn't stop, but we may have gotten
+ // a signal or the user may have requested to stop in some other
+ // way. Stop if we have a valid exception (this thread won't if
+ // another thread was the reason this process stopped) and that
+ // exception, is NOT a breakpoint exception (a common case would
+ // be a SIGINT signal).
+ if (GetStopException().IsValid() && !GetStopException().IsBreakpoint())
+ return true;
+ }
+ }
+ else
+ {
+ if (m_arch.StepNotComplete())
+ {
+ step_more = true;
+ return false;
+ }
+ // The thread state is used to let us know what the thread was
+ // trying to do. MachThread::ThreadWillResume() will set the
+ // thread state to various values depending if the thread was
+ // the current thread and if it was to be single stepped, or
+ // resumed.
+ if (GetState() == eStateRunning)
+ {
+ // If our state is running, then we should continue as we are in
+ // the process of stepping over a breakpoint.
+ return false;
+ }
+ else
+ {
+ // Stop if we have any kind of valid exception for this
+ // thread.
+ if (GetStopException().IsValid())
+ return true;
+ }
+ }
+ return false;
+}
+bool
+MachThread::IsStepping()
+{
+ // Return true if this thread is currently being stepped.
+ // MachThread::ThreadWillResume currently determines this by looking if we
+ // have been asked to single step, or if we are at a breakpoint instruction
+ // and have been asked to resume. In the latter case we need to disable the
+ // breakpoint we are at, single step, re-enable and continue.
+ nub_state_t state = GetState();
+ return (state == eStateStepping) ||
+ (state == eStateRunning && NUB_BREAK_ID_IS_VALID(CurrentBreakpoint()));
+}
+
+
+bool
+MachThread::ThreadDidStop()
+{
+ // This thread has existed prior to resuming under debug nub control,
+ // and has just been stopped. Do any cleanup that needs to be done
+ // after running.
+
+ // The thread state and breakpoint will still have the same values
+ // as they had prior to resuming the thread, so it makes it easy to check
+ // if we were trying to step a thread, or we tried to resume while being
+ // at a breakpoint.
+
+ // When this method gets called, the process state is still in the
+ // state it was in while running so we can act accordingly.
+ m_arch.ThreadDidStop();
+
+
+ // We may have suspended this thread so the primary thread could step
+ // without worrying about race conditions, so lets restore our suspend
+ // count.
+ RestoreSuspendCount();
+
+ // Update the basic information for a thread
+ MachThread::GetBasicInfo(m_tid, &m_basicInfo);
+ m_suspendCount = m_basicInfo.suspend_count;
+
+ // See if we were at a breakpoint when we last resumed that we disabled,
+ // re-enable it.
+ nub_break_t breakID = CurrentBreakpoint();
+
+ if (NUB_BREAK_ID_IS_VALID(breakID))
+ {
+ m_process->EnableBreakpoint(breakID);
+ if (m_suspendCount > 0)
+ {
+ SetState(eStateSuspended);
+ }
+ else
+ {
+ // If we last were at a breakpoint and we single stepped, our state
+ // will be "running" to indicate we need to continue after stepping
+ // over the breakpoint instruction. If we step over a breakpoint
+ // instruction, we need to stop.
+ if (GetState() == eStateRunning)
+ {
+ // Leave state set to running so we will continue automatically
+ // from this breakpoint
+ }
+ else
+ {
+ SetState(eStateStopped);
+ }
+ }
+ }
+ else
+ {
+ if (m_suspendCount > 0)
+ {
+ SetState(eStateSuspended);
+ }
+ else
+ {
+ SetState(eStateStopped);
+ }
+ }
+
+
+ SetCurrentBreakpoint(INVALID_NUB_BREAK_ID);
+
+ return true;
+}
+
+bool
+MachThread::NotifyException(MachException::Data& exc)
+{
+ if (m_stop_exception.IsValid())
+ {
+ // We may have more than one exception for a thread, but we need to
+ // only remember the one that we will say is the reason we stopped.
+ // We may have been single stepping and also gotten a signal exception,
+ // so just remember the most pertinent one.
+ if (m_stop_exception.IsBreakpoint())
+ m_stop_exception = exc;
+ }
+ else
+ {
+ m_stop_exception = exc;
+ }
+ bool handled = m_arch.NotifyException(exc);
+ if (!handled)
+ {
+ handled = true;
+ nub_addr_t pc = GetPC();
+ nub_break_t breakID = m_process->Breakpoints().FindIDByAddress(pc);
+ SetCurrentBreakpoint(breakID);
+ switch (exc.exc_type)
+ {
+ case EXC_BAD_ACCESS:
+ break;
+ case EXC_BAD_INSTRUCTION:
+ break;
+ case EXC_ARITHMETIC:
+ break;
+ case EXC_EMULATION:
+ break;
+ case EXC_SOFTWARE:
+ break;
+ case EXC_BREAKPOINT:
+ break;
+ case EXC_SYSCALL:
+ break;
+ case EXC_MACH_SYSCALL:
+ break;
+ case EXC_RPC_ALERT:
+ break;
+ }
+ }
+ return handled;
+}
+
+
+nub_state_t
+MachThread::GetState()
+{
+ // If any other threads access this we will need a mutex for it
+ PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
+ return m_state;
+}
+
+void
+MachThread::SetState(nub_state_t state)
+{
+ PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
+ m_state = state;
+ DNBLogThreadedIf(LOG_THREAD, "MachThread::SetState ( %s ) for tid = 0x%4.4x", DNBStateAsString(state), m_tid);
+}
+
+uint32_t
+MachThread::GetNumRegistersInSet(int regSet) const
+{
+ if (regSet < m_regSets.size())
+ return m_regSets[regSet].num_registers;
+ return 0;
+}
+
+const char *
+MachThread::GetRegisterSetName(int regSet) const
+{
+ if (regSet < m_regSets.size())
+ return m_regSets[regSet].name;
+ return NULL;
+}
+
+const DNBRegisterInfo *
+MachThread::GetRegisterInfo(int regSet, int regIndex) const
+{
+ if (regSet < m_regSets.size())
+ if (regIndex < m_regSets[regSet].num_registers)
+ return &m_regSets[regSet].registers[regIndex];
+ return NULL;
+}
+void
+MachThread::DumpRegisterState(int regSet)
+{
+ if (regSet == REGISTER_SET_ALL)
+ {
+ for (regSet = 1; regSet < m_regSets.size(); regSet++)
+ DumpRegisterState(regSet);
+ }
+ else
+ {
+ if (m_arch.RegisterSetStateIsValid(regSet))
+ {
+ const size_t numRegisters = GetNumRegistersInSet(regSet);
+ size_t regIndex = 0;
+ DNBRegisterValueClass reg;
+ for (regIndex = 0; regIndex < numRegisters; ++regIndex)
+ {
+ if (m_arch.GetRegisterValue(regSet, regIndex, &reg))
+ {
+ reg.Dump(NULL, NULL);
+ }
+ }
+ }
+ else
+ {
+ DNBLog("%s: registers are not currently valid.", GetRegisterSetName(regSet));
+ }
+ }
+}
+
+const DNBRegisterSetInfo *
+MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets ) const
+{
+ *num_reg_sets = m_regSets.size();
+ return &m_regSets[0];
+}
+
+bool
+MachThread::GetRegisterValue ( uint32_t set, uint32_t reg, DNBRegisterValue *value )
+{
+ return m_arch.GetRegisterValue(set, reg, value);
+}
+
+bool
+MachThread::SetRegisterValue ( uint32_t set, uint32_t reg, const DNBRegisterValue *value )
+{
+ return m_arch.SetRegisterValue(set, reg, value);
+}
+
+nub_size_t
+MachThread::GetRegisterContext (void *buf, nub_size_t buf_len)
+{
+ return m_arch.GetRegisterContext(buf, buf_len);
+}
+
+nub_size_t
+MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len)
+{
+ return m_arch.SetRegisterContext(buf, buf_len);
+}
+
+uint32_t
+MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp)
+{
+ if (bp != NULL && bp->IsBreakpoint())
+ return m_arch.EnableHardwareBreakpoint(bp->Address(), bp->ByteSize());
+ return INVALID_NUB_HW_INDEX;
+}
+
+uint32_t
+MachThread::EnableHardwareWatchpoint (const DNBBreakpoint *wp)
+{
+ if (wp != NULL && wp->IsWatchpoint())
+ return m_arch.EnableHardwareWatchpoint(wp->Address(), wp->ByteSize(), wp->WatchpointRead(), wp->WatchpointWrite());
+ return INVALID_NUB_HW_INDEX;
+}
+
+bool
+MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp)
+{
+ if (bp != NULL && bp->IsHardware())
+ return m_arch.DisableHardwareBreakpoint(bp->GetHardwareIndex());
+ return false;
+}
+
+bool
+MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp)
+{
+ if (wp != NULL && wp->IsHardware())
+ return m_arch.DisableHardwareWatchpoint(wp->GetHardwareIndex());
+ return false;
+}
+
+
+void
+MachThread::NotifyBreakpointChanged (const DNBBreakpoint *bp)
+{
+ nub_break_t breakID = bp->GetID();
+ if (bp->IsEnabled())
+ {
+ if (bp->Address() == GetPC())
+ {
+ SetCurrentBreakpoint(breakID);
+ }
+ }
+ else
+ {
+ if (CurrentBreakpoint() == breakID)
+ {
+ SetCurrentBreakpoint(INVALID_NUB_BREAK_ID);
+ }
+ }
+}
+
+bool
+MachThread::GetIdentifierInfo ()
+{
+#ifdef THREAD_IDENTIFIER_INFO_COUNT
+ if (m_ident_info.thread_id == 0)
+ {
+ mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
+ return ::thread_info (ThreadID(), THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count) == KERN_SUCCESS;
+ }
+#endif
+
+ return false;
+}
+
+
+const char *
+MachThread::GetName ()
+{
+ if (GetIdentifierInfo ())
+ {
+ int len = ::proc_pidinfo (m_process->ProcessID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo));
+
+ if (len && m_proc_threadinfo.pth_name[0])
+ return m_proc_threadinfo.pth_name;
+ }
+ return NULL;
+}
+
+
+//
+//const char *
+//MachThread::GetDispatchQueueName()
+//{
+// if (GetIdentifierInfo ())
+// {
+// if (m_ident_info.dispatch_qaddr == 0)
+// return NULL;
+//
+// uint8_t memory_buffer[8];
+// DNBDataRef data(memory_buffer, sizeof(memory_buffer), false);
+// ModuleSP module_sp(GetProcess()->GetTarget().GetImages().FindFirstModuleForFileSpec (FileSpec("libSystem.B.dylib")));
+// if (module_sp.get() == NULL)
+// return NULL;
+//
+// lldb::addr_t dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS;
+// const Symbol *dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (ConstString("dispatch_queue_offsets"), eSymbolTypeData);
+// if (dispatch_queue_offsets_symbol)
+// dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetValue().GetLoadAddress(GetProcess());
+//
+// if (dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
+// return NULL;
+//
+// // Excerpt from src/queue_private.h
+// struct dispatch_queue_offsets_s
+// {
+// uint16_t dqo_version;
+// uint16_t dqo_label;
+// uint16_t dqo_label_size;
+// } dispatch_queue_offsets;
+//
+//
+// if (GetProcess()->ReadMemory (dispatch_queue_offsets_addr, memory_buffer, sizeof(dispatch_queue_offsets)) == sizeof(dispatch_queue_offsets))
+// {
+// uint32_t data_offset = 0;
+// if (data.GetU16(&data_offset, &dispatch_queue_offsets.dqo_version, sizeof(dispatch_queue_offsets)/sizeof(uint16_t)))
+// {
+// if (GetProcess()->ReadMemory (m_ident_info.dispatch_qaddr, &memory_buffer, data.GetAddressByteSize()) == data.GetAddressByteSize())
+// {
+// data_offset = 0;
+// lldb::addr_t queue_addr = data.GetAddress(&data_offset);
+// lldb::addr_t label_addr = queue_addr + dispatch_queue_offsets.dqo_label;
+// const size_t chunk_size = 32;
+// uint32_t label_pos = 0;
+// m_dispatch_queue_name.resize(chunk_size, '\0');
+// while (1)
+// {
+// size_t bytes_read = GetProcess()->ReadMemory (label_addr + label_pos, &m_dispatch_queue_name[label_pos], chunk_size);
+//
+// if (bytes_read <= 0)
+// break;
+//
+// if (m_dispatch_queue_name.find('\0', label_pos) != std::string::npos)
+// break;
+// label_pos += bytes_read;
+// }
+// m_dispatch_queue_name.erase(m_dispatch_queue_name.find('\0'));
+// }
+// }
+// }
+// }
+//
+// if (m_dispatch_queue_name.empty())
+// return NULL;
+// return m_dispatch_queue_name.c_str();
+//}
diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.h b/lldb/tools/debugserver/source/MacOSX/MachThread.h
new file mode 100644
index 00000000000..2bf5ff2c3bb
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachThread.h
@@ -0,0 +1,124 @@
+//===-- MachThread.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/19/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __MachThread_h__
+#define __MachThread_h__
+
+#include <string>
+#include <vector>
+#include <tr1/memory> // for std::tr1::shared_ptr
+
+#include <libproc.h>
+#include <mach/mach.h>
+#include <pthread.h>
+#include <sys/signal.h>
+
+#include "PThreadCondition.h"
+#include "PThreadMutex.h"
+#include "MachException.h"
+#include "DNBArch.h"
+#include "DNBRegisterInfo.h"
+
+class DNBBreakpoint;
+class MachProcess;
+
+class MachThread
+{
+public:
+
+ MachThread (MachProcess *process, thread_t thread = 0);
+ ~MachThread ();
+
+ MachProcess * Process() { return m_process; }
+ const MachProcess *
+ Process() const { return m_process; }
+ nub_process_t ProcessID() const;
+ void Dump(uint32_t index);
+ thread_t ThreadID() const { return m_tid; }
+ thread_t InferiorThreadID() const;
+
+ uint32_t SequenceID() const { return m_seq_id; }
+ static bool ThreadIDIsValid(thread_t thread);
+ uint32_t Resume();
+ uint32_t Suspend();
+ uint32_t SuspendCount() const { return m_suspendCount; }
+ bool RestoreSuspendCount();
+
+ bool GetRegisterState(int flavor, bool force);
+ bool SetRegisterState(int flavor);
+ uint64_t GetPC(uint64_t failValue = INVALID_NUB_ADDRESS); // Get program counter
+ bool SetPC(uint64_t value); // Set program counter
+ uint64_t GetSP(uint64_t failValue = INVALID_NUB_ADDRESS); // Get stack pointer
+
+ nub_break_t CurrentBreakpoint() const { return m_breakID; }
+ void SetCurrentBreakpoint(nub_break_t breakID) { m_breakID = breakID; }
+ uint32_t EnableHardwareBreakpoint (const DNBBreakpoint *breakpoint);
+ uint32_t EnableHardwareWatchpoint (const DNBBreakpoint *watchpoint);
+ bool DisableHardwareBreakpoint (const DNBBreakpoint *breakpoint);
+ bool DisableHardwareWatchpoint (const DNBBreakpoint *watchpoint);
+
+ nub_state_t GetState();
+ void SetState(nub_state_t state);
+
+ void ThreadWillResume (const DNBThreadResumeAction *thread_action);
+ bool ShouldStop(bool &step_more);
+ bool IsStepping();
+ bool ThreadDidStop();
+ bool NotifyException(MachException::Data& exc);
+ const MachException::Data& GetStopException() { return m_stop_exception; }
+
+ uint32_t GetNumRegistersInSet(int regSet) const;
+ const char * GetRegisterSetName(int regSet) const;
+ const DNBRegisterInfo *
+ GetRegisterInfo(int regSet, int regIndex) const;
+ void DumpRegisterState(int regSet);
+ const DNBRegisterSetInfo *
+ GetRegisterSetInfo(nub_size_t *num_reg_sets ) const;
+ bool GetRegisterValue ( uint32_t reg_set_idx, uint32_t reg_idx, DNBRegisterValue *reg_value );
+ bool SetRegisterValue ( uint32_t reg_set_idx, uint32_t reg_idx, const DNBRegisterValue *reg_value );
+ nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len);
+ nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len);
+ void NotifyBreakpointChanged (const DNBBreakpoint *bp);
+ const char * GetBasicInfoAsString () const;
+ const char * GetName ();
+protected:
+ static bool GetBasicInfo(thread_t threadID, struct thread_basic_info *basic_info);
+
+ bool
+ GetIdentifierInfo ();
+
+// const char *
+// GetDispatchQueueName();
+//
+ MachProcess * m_process; // The process that owns this thread
+ thread_t m_tid; // The thread port for this thread
+ uint32_t m_seq_id; // A Sequential ID that increments with each new thread
+ nub_state_t m_state; // The state of our process
+ PThreadMutex m_state_mutex; // Multithreaded protection for m_state
+ nub_break_t m_breakID; // Breakpoint that this thread is (stopped)/was(running) at (NULL for none)
+ struct thread_basic_info m_basicInfo; // Basic information for a thread used to see if a thread is valid
+ uint32_t m_suspendCount; // The current suspend count
+ MachException::Data m_stop_exception; // The best exception that describes why this thread is stopped
+ DNBArch m_arch; // Arch specific information for register state and more
+ std::vector<DNBRegisterSetInfo> m_regSets; // Register set information for this thread
+#ifdef THREAD_IDENTIFIER_INFO_COUNT
+ thread_identifier_info_data_t m_ident_info;
+ struct proc_threadinfo m_proc_threadinfo;
+ std::string m_dispatch_queue_name;
+#endif
+
+};
+
+typedef std::tr1::shared_ptr<MachThread> MachThreadSP;
+
+#endif
diff --git a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp
new file mode 100644
index 00000000000..b1ccc74f8e6
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp
@@ -0,0 +1,432 @@
+//===-- MachThreadList.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/19/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachThreadList.h"
+#include "DNBLog.h"
+#include "DNBThreadResumeActions.h"
+#include "MachProcess.h"
+
+MachThreadList::MachThreadList() :
+ m_threads(),
+ m_threads_mutex(PTHREAD_MUTEX_RECURSIVE)
+{
+}
+
+MachThreadList::~MachThreadList()
+{
+}
+
+// Not thread safe, must lock m_threads_mutex prior to using this function.
+uint32_t
+MachThreadList::GetThreadIndexByID(thread_t tid) const
+{
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->ThreadID() == tid)
+ return idx;
+ }
+ return ~((uint32_t)0);
+}
+
+nub_state_t
+MachThreadList::GetState(thread_t tid)
+{
+ uint32_t idx = GetThreadIndexByID(tid);
+ if (idx < m_threads.size())
+ return m_threads[idx]->GetState();
+ return eStateInvalid;
+}
+
+const char *
+MachThreadList::GetName (thread_t tid)
+{
+ uint32_t idx = GetThreadIndexByID(tid);
+ if (idx < m_threads.size())
+ return m_threads[idx]->GetName();
+ return NULL;
+}
+
+nub_thread_t
+MachThreadList::SetCurrentThread(thread_t tid)
+{
+ uint32_t idx = GetThreadIndexByID(tid);
+ if (idx < m_threads.size())
+ m_current_thread = m_threads[idx];
+
+ if (m_current_thread.get())
+ return m_current_thread->ThreadID();
+ return INVALID_NUB_THREAD;
+}
+
+
+bool
+MachThreadList::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const
+{
+ uint32_t idx = GetThreadIndexByID(tid);
+ if (idx < m_threads.size())
+ return m_threads[idx]->GetStopException().GetStopInfo(stop_info);
+ return false;
+}
+
+bool
+MachThreadList::GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info)
+{
+ mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
+ return ::thread_info (tid, THREAD_IDENTIFIER_INFO, (thread_info_t)ident_info, &count) == KERN_SUCCESS;
+}
+
+void
+MachThreadList::DumpThreadStoppedReason(nub_thread_t tid) const
+{
+ uint32_t idx = GetThreadIndexByID(tid);
+ if (idx < m_threads.size())
+ m_threads[idx]->GetStopException().DumpStopReason();
+}
+
+const char *
+MachThreadList::GetThreadInfo(nub_thread_t tid) const
+{
+ uint32_t idx = GetThreadIndexByID(tid);
+ if (idx < m_threads.size())
+ return m_threads[idx]->GetBasicInfoAsString();
+ return NULL;
+}
+
+bool
+MachThreadList::GetRegisterValue ( nub_thread_t tid, uint32_t reg_set_idx, uint32_t reg_idx, DNBRegisterValue *reg_value ) const
+{
+ uint32_t idx = GetThreadIndexByID(tid);
+ if (idx < m_threads.size())
+ return m_threads[idx]->GetRegisterValue(reg_set_idx, reg_idx, reg_value);
+
+ return false;
+}
+
+bool
+MachThreadList::SetRegisterValue ( nub_thread_t tid, uint32_t reg_set_idx, uint32_t reg_idx, const DNBRegisterValue *reg_value ) const
+{
+ uint32_t idx = GetThreadIndexByID(tid);
+ if (idx < m_threads.size())
+ return m_threads[idx]->SetRegisterValue(reg_set_idx, reg_idx, reg_value);
+
+ return false;
+}
+
+nub_size_t
+MachThreadList::GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len)
+{
+ uint32_t idx = GetThreadIndexByID(tid);
+ if (idx < m_threads.size())
+ return m_threads[idx]->GetRegisterContext (buf, buf_len);
+ return 0;
+}
+
+nub_size_t
+MachThreadList::SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len)
+{
+ uint32_t idx = GetThreadIndexByID(tid);
+ if (idx < m_threads.size())
+ return m_threads[idx]->SetRegisterContext (buf, buf_len);
+ return 0;
+}
+
+nub_size_t
+MachThreadList::NumThreads() const
+{
+ return m_threads.size();
+}
+
+nub_thread_t
+MachThreadList::ThreadIDAtIndex(nub_size_t idx) const
+{
+ if (idx < m_threads.size())
+ return m_threads[idx]->ThreadID();
+ return INVALID_NUB_THREAD;
+}
+
+nub_thread_t
+MachThreadList::CurrentThreadID ( )
+{
+ MachThreadSP threadSP;
+ CurrentThread(threadSP);
+ if (threadSP.get())
+ return threadSP->ThreadID();
+ return INVALID_NUB_THREAD;
+}
+
+bool
+MachThreadList::NotifyException(MachException::Data& exc)
+{
+ uint32_t idx = GetThreadIndexByID(exc.thread_port);
+ if (idx < m_threads.size())
+ {
+ m_threads[idx]->NotifyException(exc);
+ return true;
+ }
+ return false;
+}
+
+/*
+MachThreadList::const_iterator
+MachThreadList::FindThreadByID(thread_t tid) const
+{
+ const_iterator pos;
+ const_iterator end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ if (pos->ThreadID() == tid)
+ return pos;
+ }
+ return NULL;
+}
+*/
+void
+MachThreadList::Clear()
+{
+ m_threads.clear();
+}
+
+uint32_t
+MachThreadList::UpdateThreadList(MachProcess *process, bool update)
+{
+ // locker will keep a mutex locked until it goes out of scope
+ DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThreadList::UpdateThreadList (pid = %4.4x, update = %u )", process->ProcessID(), update);
+ PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
+
+ if (m_threads.empty() || update)
+ {
+ thread_array_t thread_list = NULL;
+ mach_msg_type_number_t thread_list_count = 0;
+ task_t task = process->Task().TaskPort();
+ DNBError err(::task_threads (task, &thread_list, &thread_list_count), DNBError::MachKernel);
+
+ if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
+ err.LogThreaded("::task_threads ( task = 0x%4.4x, thread_list => %p, thread_list_count => %u )", task, thread_list, thread_list_count);
+
+ if (err.Error() == KERN_SUCCESS && thread_list_count > 0)
+ {
+ MachThreadList::collection currThreads;
+ const size_t numOldThreads = m_threads.size();
+ size_t idx;
+ // Iterator through the current thread list and see which threads
+ // we already have in our list (keep them), which ones we don't
+ // (add them), and which ones are not around anymore (remove them).
+ for (idx = 0; idx < thread_list_count; ++idx)
+ {
+ uint32_t existing_idx = 0;
+ if (numOldThreads > 0)
+ existing_idx = GetThreadIndexByID(thread_list[idx]);
+ if (existing_idx < numOldThreads)
+ {
+ // Keep the existing thread class
+ currThreads.push_back(m_threads[existing_idx]);
+ }
+ else
+ {
+ // We don't have this thread, lets add it.
+ MachThreadSP threadSP(new MachThread(process, thread_list[idx]));
+ currThreads.push_back(threadSP);
+ }
+ }
+
+ m_threads.swap(currThreads);
+ m_current_thread.reset();
+
+ // Free the vm memory given to us by ::task_threads()
+ vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t));
+ ::vm_deallocate (::mach_task_self(),
+ (vm_address_t)thread_list,
+ thread_list_size);
+ }
+ }
+ return m_threads.size();
+}
+
+
+void
+MachThreadList::CurrentThread(MachThreadSP& threadSP)
+{
+ // locker will keep a mutex locked until it goes out of scope
+ PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
+ if (m_current_thread.get() == NULL)
+ {
+ // Figure out which thread is going to be our current thread.
+ // This is currently done by finding the first thread in the list
+ // that has a valid exception.
+ const size_t num_threads = m_threads.size();
+ size_t idx;
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ MachThread *thread = m_threads[idx].get();
+ if (thread->GetStopException().IsValid())
+ {
+ m_current_thread = m_threads[idx];
+ break;
+ }
+ }
+ }
+ threadSP = m_current_thread;
+}
+
+void
+MachThreadList::GetRegisterState(int flavor, bool force)
+{
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ m_threads[idx]->GetRegisterState(flavor, force);
+ }
+}
+
+void
+MachThreadList::SetRegisterState(int flavor)
+{
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ m_threads[idx]->SetRegisterState(flavor);
+ }
+}
+
+void
+MachThreadList::Dump() const
+{
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ m_threads[idx]->Dump(idx);
+ }
+}
+
+
+void
+MachThreadList::ProcessWillResume(MachProcess *process, const DNBThreadResumeActions &thread_actions)
+{
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ MachThread *thread = m_threads[idx].get();
+
+ const DNBThreadResumeAction *thread_action = thread_actions.GetActionForThread (thread->ThreadID(), true);
+ // There must always be a thread action for every thread.
+ assert (thread_action);
+ thread->ThreadWillResume (thread_action);
+ }
+}
+
+uint32_t
+MachThreadList::ProcessDidStop(MachProcess *process)
+{
+ // Update our thread list
+ const uint32_t num_threads = UpdateThreadList(process, true);
+ uint32_t idx = 0;
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ m_threads[idx]->ThreadDidStop();
+ }
+ return num_threads;
+}
+
+//----------------------------------------------------------------------
+// Check each thread in our thread list to see if we should notify our
+// client of the current halt in execution.
+//
+// Breakpoints can have callback functions associated with them than
+// can return true to stop, or false to continue executing the inferior.
+//
+// RETURNS
+// true if we should stop and notify our clients
+// false if we should resume our child process and skip notification
+//----------------------------------------------------------------------
+bool
+MachThreadList::ShouldStop(bool &step_more)
+{
+ uint32_t should_stop = false;
+ const uint32_t num_threads = m_threads.size();
+ uint32_t idx = 0;
+ for (idx = 0; !should_stop && idx < num_threads; ++idx)
+ {
+ should_stop = m_threads[idx]->ShouldStop(step_more);
+ }
+ return should_stop;
+}
+
+
+void
+MachThreadList::NotifyBreakpointChanged (const DNBBreakpoint *bp)
+{
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ m_threads[idx]->NotifyBreakpointChanged(bp);
+ }
+}
+
+
+uint32_t
+MachThreadList::EnableHardwareBreakpoint (const DNBBreakpoint* bp) const
+{
+ if (bp != NULL)
+ {
+ uint32_t idx = GetThreadIndexByID(bp->ThreadID());
+ if (idx < m_threads.size())
+ return m_threads[idx]->EnableHardwareBreakpoint(bp);
+ }
+ return INVALID_NUB_HW_INDEX;
+}
+
+bool
+MachThreadList::DisableHardwareBreakpoint (const DNBBreakpoint* bp) const
+{
+ if (bp != NULL)
+ {
+ uint32_t idx = GetThreadIndexByID(bp->ThreadID());
+ if (idx < m_threads.size())
+ return m_threads[idx]->DisableHardwareBreakpoint(bp);
+ }
+ return false;
+}
+
+uint32_t
+MachThreadList::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const
+{
+ if (wp != NULL)
+ {
+ uint32_t idx = GetThreadIndexByID(wp->ThreadID());
+ if (idx < m_threads.size())
+ return m_threads[idx]->EnableHardwareWatchpoint(wp);
+ }
+ return INVALID_NUB_HW_INDEX;
+}
+
+bool
+MachThreadList::DisableHardwareWatchpoint (const DNBBreakpoint* wp) const
+{
+ if (wp != NULL)
+ {
+ uint32_t idx = GetThreadIndexByID(wp->ThreadID());
+ if (idx < m_threads.size())
+ return m_threads[idx]->DisableHardwareWatchpoint(wp);
+ }
+ return false;
+}
+
+
diff --git a/lldb/tools/debugserver/source/MacOSX/MachThreadList.h b/lldb/tools/debugserver/source/MacOSX/MachThreadList.h
new file mode 100644
index 00000000000..b52a97b547b
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachThreadList.h
@@ -0,0 +1,71 @@
+//===-- MachThreadList.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/19/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __MachThreadList_h__
+#define __MachThreadList_h__
+
+#include "MachThread.h"
+
+class DNBThreadResumeActions;
+
+class MachThreadList
+{
+public:
+ MachThreadList ();
+ ~MachThreadList ();
+
+ void Clear ();
+ void Dump () const;
+ void GetRegisterState (int flavor, bool force);
+ void SetRegisterState (int flavor);
+ bool GetRegisterValue (nub_thread_t tid, uint32_t reg_set_idx, uint32_t reg_idx, DNBRegisterValue *reg_value) const;
+ bool SetRegisterValue (nub_thread_t tid, uint32_t reg_set_idx, uint32_t reg_idx, const DNBRegisterValue *reg_value) const;
+ nub_size_t GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len);
+ nub_size_t SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len);
+ const char * GetThreadInfo (nub_thread_t tid) const;
+ void ProcessWillResume (MachProcess *process, const DNBThreadResumeActions &thread_actions);
+ uint32_t ProcessDidStop (MachProcess *process);
+ bool NotifyException (MachException::Data& exc);
+ bool ShouldStop (bool &step_more);
+ const char * GetName (thread_t tid);
+ nub_state_t GetState (thread_t tid);
+ nub_thread_t SetCurrentThread (thread_t tid);
+ bool GetThreadStoppedReason (nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const;
+ void DumpThreadStoppedReason (nub_thread_t tid) const;
+ bool GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info);
+ nub_size_t NumThreads () const;
+ nub_thread_t ThreadIDAtIndex (nub_size_t idx) const;
+ nub_thread_t CurrentThreadID ();
+ uint32_t GetThreadIndexByID (thread_t tid) const;
+ void CurrentThread (MachThreadSP& threadSP);
+ void NotifyBreakpointChanged (const DNBBreakpoint *bp);
+ uint32_t EnableHardwareBreakpoint (const DNBBreakpoint *bp) const;
+ bool DisableHardwareBreakpoint (const DNBBreakpoint *bp) const;
+ uint32_t EnableHardwareWatchpoint (const DNBBreakpoint *wp) const;
+ bool DisableHardwareWatchpoint (const DNBBreakpoint *wp) const;
+
+protected:
+ typedef std::vector<MachThreadSP> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ uint32_t UpdateThreadList (MachProcess *process, bool update);
+// const_iterator FindThreadByID (thread_t tid) const;
+
+ collection m_threads;
+ PThreadMutex m_threads_mutex;
+ MachThreadSP m_current_thread;
+};
+
+#endif // #ifndef __MachThreadList_h__
+
diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp
new file mode 100644
index 00000000000..eb7e10746e2
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp
@@ -0,0 +1,186 @@
+//===-- MachVMMemory.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/26/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachVMMemory.h"
+#include "MachVMRegion.h"
+#include "DNBLog.h"
+#include <mach/mach_vm.h>
+
+MachVMMemory::MachVMMemory() :
+ m_page_size (kInvalidPageSize),
+ m_err (0)
+{
+}
+
+MachVMMemory::~MachVMMemory()
+{
+}
+
+nub_size_t
+MachVMMemory::PageSize()
+{
+ if (m_page_size == kInvalidPageSize)
+ {
+ m_err = ::host_page_size( ::mach_host_self(), &m_page_size);
+ if (m_err.Fail())
+ m_page_size = 0;
+ }
+ return m_page_size;
+}
+
+nub_size_t
+MachVMMemory::MaxBytesLeftInPage(nub_addr_t addr, nub_size_t count)
+{
+ const nub_size_t page_size = PageSize();
+ if (page_size > 0)
+ {
+ nub_size_t page_offset = (addr % page_size);
+ nub_size_t bytes_left_in_page = page_size - page_offset;
+ if (count > bytes_left_in_page)
+ count = bytes_left_in_page;
+ }
+ return count;
+}
+
+nub_size_t
+MachVMMemory::Read(task_t task, nub_addr_t address, void *data, nub_size_t data_count)
+{
+ if (data == NULL || data_count == 0)
+ return 0;
+
+ nub_size_t total_bytes_read = 0;
+ nub_addr_t curr_addr = address;
+ uint8_t *curr_data = (uint8_t*)data;
+ while (total_bytes_read < data_count)
+ {
+ mach_vm_size_t curr_size = MaxBytesLeftInPage(curr_addr, data_count - total_bytes_read);
+ mach_msg_type_number_t curr_bytes_read = 0;
+ vm_offset_t vm_memory = NULL;
+ m_err = ::mach_vm_read (task, curr_addr, curr_size, &vm_memory, &curr_bytes_read);
+ if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail())
+ m_err.LogThreaded("::mach_vm_read ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt => %i )", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read);
+
+ if (m_err.Success())
+ {
+ if (curr_bytes_read != curr_size)
+ {
+ if (DNBLogCheckLogBit(LOG_MEMORY))
+ m_err.LogThreaded("::mach_vm_read ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt=>%i ) only read %u of %llu bytes", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read, curr_bytes_read, (uint64_t)curr_size);
+ }
+ ::memcpy (curr_data, (void *)vm_memory, curr_bytes_read);
+ ::vm_deallocate (mach_task_self (), vm_memory, curr_bytes_read);
+ total_bytes_read += curr_bytes_read;
+ curr_addr += curr_bytes_read;
+ curr_data += curr_bytes_read;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return total_bytes_read;
+}
+
+
+nub_size_t
+MachVMMemory::Write(task_t task, nub_addr_t address, const void *data, nub_size_t data_count)
+{
+ MachVMRegion vmRegion(task);
+
+ nub_size_t total_bytes_written = 0;
+ nub_addr_t curr_addr = address;
+ const uint8_t *curr_data = (const uint8_t*)data;
+
+
+ while (total_bytes_written < data_count)
+ {
+ if (vmRegion.GetRegionForAddress(curr_addr))
+ {
+ mach_vm_size_t curr_data_count = data_count - total_bytes_written;
+ mach_vm_size_t region_bytes_left = vmRegion.BytesRemaining(curr_addr);
+ if (region_bytes_left == 0)
+ {
+ break;
+ }
+ if (curr_data_count > region_bytes_left)
+ curr_data_count = region_bytes_left;
+
+ if (vmRegion.SetProtections(curr_addr, curr_data_count, VM_PROT_READ | VM_PROT_WRITE))
+ {
+ nub_size_t bytes_written = WriteRegion(task, curr_addr, curr_data, curr_data_count);
+ if (bytes_written <= 0)
+ {
+ // Error should have already be posted by WriteRegion...
+ break;
+ }
+ else
+ {
+ total_bytes_written += bytes_written;
+ curr_addr += bytes_written;
+ curr_data += bytes_written;
+ }
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS, "Failed to set read/write protections on region for address: [0x%8.8llx-0x%8.8llx)", (uint64_t)curr_addr, (uint64_t)(curr_addr + curr_data_count));
+ break;
+ }
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS, "Failed to get region for address: 0x%8.8llx", (uint64_t)address);
+ break;
+ }
+ }
+
+ return total_bytes_written;
+}
+
+
+nub_size_t
+MachVMMemory::WriteRegion(task_t task, const nub_addr_t address, const void *data, const nub_size_t data_count)
+{
+ if (data == NULL || data_count == 0)
+ return 0;
+
+ nub_size_t total_bytes_written = 0;
+ nub_addr_t curr_addr = address;
+ const uint8_t *curr_data = (const uint8_t*)data;
+ while (total_bytes_written < data_count)
+ {
+ mach_msg_type_number_t curr_data_count = MaxBytesLeftInPage(curr_addr, data_count - total_bytes_written);
+ m_err = ::mach_vm_write (task, curr_addr, (pointer_t) curr_data, curr_data_count);
+ if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail())
+ m_err.LogThreaded("::mach_vm_write ( task = 0x%4.4x, addr = 0x%8.8llx, data = %8.8p, dataCnt = %u )", task, (uint64_t)curr_addr, curr_data, curr_data_count);
+
+#if !defined (__i386__) && !defined (__x86_64__)
+ vm_machine_attribute_val_t mattr_value = MATTR_VAL_CACHE_FLUSH;
+
+ m_err = ::vm_machine_attribute (task, curr_addr, curr_data_count, MATTR_CACHE, &mattr_value);
+ if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail())
+ m_err.LogThreaded("::vm_machine_attribute ( task = 0x%4.4x, addr = 0x%8.8llx, size = %u, attr = MATTR_CACHE, mattr_value => MATTR_VAL_CACHE_FLUSH )", task, (uint64_t)curr_addr, curr_data_count);
+#endif
+
+ if (m_err.Success())
+ {
+ total_bytes_written += curr_data_count;
+ curr_addr += curr_data_count;
+ curr_data += curr_data_count;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return total_bytes_written;
+}
diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.h b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.h
new file mode 100644
index 00000000000..5635186854a
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.h
@@ -0,0 +1,40 @@
+//===-- MachVMMemory.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/26/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __MachVMMemory_h__
+#define __MachVMMemory_h__
+
+#include "DNBDefs.h"
+#include "DNBError.h"
+#include <mach/mach.h>
+
+class MachVMMemory
+{
+public:
+ enum { kInvalidPageSize = ~0 };
+ MachVMMemory();
+ ~MachVMMemory();
+ nub_size_t Read(task_t task, nub_addr_t address, void *data, nub_size_t data_count);
+ nub_size_t Write(task_t task, nub_addr_t address, const void *data, nub_size_t data_count);
+ nub_size_t PageSize();
+
+protected:
+ nub_size_t MaxBytesLeftInPage(nub_addr_t addr, nub_size_t count);
+
+ nub_size_t WriteRegion(task_t task, const nub_addr_t address, const void *data, const nub_size_t data_count);
+ vm_size_t m_page_size;
+ DNBError m_err;
+};
+
+
+#endif // #ifndef __MachVMMemory_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp b/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp
new file mode 100644
index 00000000000..6299cf4179f
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp
@@ -0,0 +1,179 @@
+//===-- MachVMRegion.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/26/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachVMRegion.h"
+#include <mach/mach_vm.h>
+#include "DNBLog.h"
+#include <assert.h>
+
+MachVMRegion::MachVMRegion(task_t task) :
+ m_task(task),
+ m_addr(INVALID_NUB_ADDRESS),
+ m_err(),
+ m_start(INVALID_NUB_ADDRESS),
+ m_size(0),
+ m_depth(-1),
+ m_curr_protection(0),
+ m_protection_addr(INVALID_NUB_ADDRESS),
+ m_protection_size(0)
+{
+ memset(&m_data, 0, sizeof(m_data));
+}
+
+MachVMRegion::~MachVMRegion()
+{
+ // Restore any original protections and clear our vars
+ Clear();
+}
+
+void
+MachVMRegion::Clear()
+{
+ RestoreProtections();
+ m_addr = INVALID_NUB_ADDRESS;
+ m_err.Clear();
+ m_start = INVALID_NUB_ADDRESS;
+ m_size = 0;
+ m_depth = -1;
+ memset(&m_data, 0, sizeof(m_data));
+ m_curr_protection = 0;
+ m_protection_addr = INVALID_NUB_ADDRESS;
+ m_protection_size = 0;
+}
+
+bool
+MachVMRegion::SetProtections(mach_vm_address_t addr, mach_vm_size_t size, vm_prot_t prot)
+{
+ if (ContainsAddress(addr))
+ {
+ mach_vm_size_t prot_size = size;
+ mach_vm_address_t end_addr = EndAddress();
+ if (prot_size > (end_addr - addr))
+ prot_size = end_addr - addr;
+
+ if (prot_size > 0)
+ {
+ if (prot == (m_curr_protection & VM_PROT_ALL))
+ {
+ DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS | LOG_VERBOSE, "MachVMRegion::%s: protections (%u) already sufficient for task 0x%4.4x at address 0x%8.8llx) ", __FUNCTION__, prot, m_task, (uint64_t)addr);
+ // Protections are already set as requested...
+ return true;
+ }
+ else
+ {
+ m_err = ::mach_vm_protect (m_task, addr, prot_size, 0, prot);
+ if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS))
+ m_err.LogThreaded("::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)addr, (uint64_t)prot_size, 0, prot);
+ if (m_err.Fail())
+ {
+ // Try again with the ability to create a copy on write region
+ m_err = ::mach_vm_protect (m_task, addr, prot_size, 0, prot | VM_PROT_COPY);
+ if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS) || m_err.Fail())
+ m_err.LogThreaded("::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)addr, (uint64_t)prot_size, 0, prot | VM_PROT_COPY);
+ }
+ if (m_err.Success())
+ {
+ m_curr_protection = prot;
+ m_protection_addr = addr;
+ m_protection_size = prot_size;
+ return true;
+ }
+ }
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS | LOG_VERBOSE, "%s: Zero size for task 0x%4.4x at address 0x%8.8llx) ", __FUNCTION__, m_task, (uint64_t)addr);
+ }
+ }
+ return false;
+}
+
+bool
+MachVMRegion::RestoreProtections()
+{
+ if (m_curr_protection != m_data.protection && m_protection_size > 0)
+ {
+ m_err = ::mach_vm_protect (m_task, m_protection_addr, m_protection_size, 0, m_data.protection);
+ if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS) || m_err.Fail())
+ m_err.LogThreaded("::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)m_protection_addr, (uint64_t)m_protection_size, 0, m_data.protection);
+ if (m_err.Success())
+ {
+ m_protection_size = 0;
+ m_protection_addr = INVALID_NUB_ADDRESS;
+ m_curr_protection = m_data.protection;
+ return true;
+ }
+ }
+ else
+ {
+ m_err.Clear();
+ return true;
+ }
+
+ return false;
+}
+
+bool
+MachVMRegion::GetRegionForAddress(nub_addr_t addr)
+{
+ // Restore any original protections and clear our vars
+ Clear();
+ m_addr = addr;
+ m_start = addr;
+ m_depth = 1024;
+ mach_msg_type_number_t info_size = kRegionInfoSize;
+ assert(sizeof(info_size) == 4);
+ m_err = ::mach_vm_region_recurse (m_task, &m_start, &m_size, &m_depth, (vm_region_recurse_info_t)&m_data, &info_size);
+ if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS) || m_err.Fail())
+ m_err.LogThreaded("::mach_vm_region_recurse ( task = 0x%4.4x, address => 0x%8.8llx, size => %llu, nesting_depth => %d, info => %p, infoCnt => %d) addr = 0x%8.8llx ", m_task, (uint64_t)m_start, (uint64_t)m_size, m_depth, &m_data, info_size, (uint64_t)addr);
+ if (m_err.Fail())
+ {
+ return false;
+ }
+ else
+ {
+ if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS))
+ {
+ DNBLogThreaded("info = { prot = %u, "
+ "max_prot = %u, "
+ "inheritance = 0x%8.8x, "
+ "offset = 0x%8.8llx, "
+ "user_tag = 0x%8.8x, "
+ "ref_count = %u, "
+ "shadow_depth = %u, "
+ "ext_pager = %u, "
+ "share_mode = %u, "
+ "is_submap = %d, "
+ "behavior = %d, "
+ "object_id = 0x%8.8x, "
+ "user_wired_count = 0x%4.4x }",
+ m_data.protection,
+ m_data.max_protection,
+ m_data.inheritance,
+ (uint64_t)m_data.offset,
+ m_data.user_tag,
+ m_data.ref_count,
+ m_data.shadow_depth,
+ m_data.external_pager,
+ m_data.share_mode,
+ m_data.is_submap,
+ m_data.behavior,
+ m_data.object_id,
+ m_data.user_wired_count);
+ }
+ }
+
+ m_curr_protection = m_data.protection;
+
+ return true;
+}
diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMRegion.h b/lldb/tools/debugserver/source/MacOSX/MachVMRegion.h
new file mode 100644
index 00000000000..617e221a57e
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/MachVMRegion.h
@@ -0,0 +1,67 @@
+//===-- MachVMRegion.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/26/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __MachVMRegion_h__
+#define __MachVMRegion_h__
+
+#include "DNBDefs.h"
+#include "DNBError.h"
+#include <mach/mach.h>
+
+class MachVMRegion
+{
+public:
+ MachVMRegion(task_t task);
+ ~MachVMRegion();
+
+ void Clear();
+ mach_vm_address_t StartAddress() const { return m_start; }
+ mach_vm_address_t EndAddress() const { return m_start + m_size; }
+ mach_vm_address_t BytesRemaining(mach_vm_address_t addr) const
+ {
+ if (ContainsAddress(addr))
+ return m_size - (addr - m_start);
+ else
+ return 0;
+ }
+ bool ContainsAddress(mach_vm_address_t addr) const
+ {
+ return addr >= StartAddress() && addr < EndAddress();
+ }
+
+ bool SetProtections(mach_vm_address_t addr, mach_vm_size_t size, vm_prot_t prot);
+ bool RestoreProtections();
+ bool GetRegionForAddress(nub_addr_t addr);
+protected:
+#if defined (VM_REGION_SUBMAP_SHORT_INFO_COUNT_64)
+ typedef vm_region_submap_short_info_data_64_t RegionInfo;
+ enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 };
+#else
+ typedef vm_region_submap_info_data_64_t RegionInfo;
+ enum { kRegionInfoSize = VM_REGION_SUBMAP_INFO_COUNT_64 };
+#endif
+
+ task_t m_task;
+ mach_vm_address_t m_addr;
+ DNBError m_err;
+ mach_vm_address_t m_start;
+ mach_vm_size_t m_size;
+ natural_t m_depth;
+ RegionInfo m_data;
+ vm_prot_t m_curr_protection; // The current, possibly modified protections. Original value is saved in m_data.protections.
+ mach_vm_address_t m_protection_addr; // The start address at which protections were changed
+ mach_vm_size_t m_protection_size; // The size of memory that had its protections changed
+
+};
+
+#endif // #ifndef __MachVMRegion_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp
new file mode 100644
index 00000000000..6eec80cfd7a
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp
@@ -0,0 +1,2610 @@
+//===-- DNBArchImpl.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/25/07.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined (__arm__)
+
+#include "MacOSX/arm/DNBArchImpl.h"
+#include "MacOSX/MachProcess.h"
+#include "MacOSX/MachThread.h"
+#include "DNBBreakpoint.h"
+#include "DNBLog.h"
+#include "DNBRegisterInfo.h"
+#include "DNB.h"
+
+#include <sys/sysctl.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 priveleged 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))
+
+//#define DNB_ARCH_MACH_ARM_DEBUG_SW_STEP 1
+
+static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 };
+static const uint8_t g_thumb_breakpooint_opcode[] = { 0xFE, 0xDE };
+
+// ARM constants used during decoding
+#define REG_RD 0
+#define LDM_REGLIST 1
+#define PC_REG 15
+#define PC_REGLIST_BIT 0x8000
+
+// ARM conditions
+#define COND_EQ 0x0
+#define COND_NE 0x1
+#define COND_CS 0x2
+#define COND_HS 0x2
+#define COND_CC 0x3
+#define COND_LO 0x3
+#define COND_MI 0x4
+#define COND_PL 0x5
+#define COND_VS 0x6
+#define COND_VC 0x7
+#define COND_HI 0x8
+#define COND_LS 0x9
+#define COND_GE 0xA
+#define COND_LT 0xB
+#define COND_GT 0xC
+#define COND_LE 0xD
+#define COND_AL 0xE
+#define COND_UNCOND 0xF
+
+#define MASK_CPSR_T (1u << 5)
+#define MASK_CPSR_J (1u << 24)
+
+#define MNEMONIC_STRING_SIZE 32
+#define OPERAND_STRING_SIZE 128
+
+const uint8_t * const
+DNBArchMachARM::SoftwareBreakpointOpcode (nub_size_t byte_size)
+{
+ switch (byte_size)
+ {
+ case 2: return g_thumb_breakpooint_opcode;
+ case 4: return g_arm_breakpoint_opcode;
+ }
+ return NULL;
+}
+
+uint32_t
+DNBArchMachARM::GetCPUType()
+{
+ return CPU_TYPE_ARM;
+}
+
+uint64_t
+DNBArchMachARM::GetPC(uint64_t failValue)
+{
+ // Get program counter
+ if (GetGPRState(false) == KERN_SUCCESS)
+ return m_state.gpr.__pc;
+ return failValue;
+}
+
+kern_return_t
+DNBArchMachARM::SetPC(uint64_t value)
+{
+ // Get program counter
+ kern_return_t err = GetGPRState(false);
+ if (err == KERN_SUCCESS)
+ {
+ m_state.gpr.__pc = value;
+ err = SetGPRState();
+ }
+ return err == KERN_SUCCESS;
+}
+
+uint64_t
+DNBArchMachARM::GetSP(uint64_t failValue)
+{
+ // Get stack pointer
+ if (GetGPRState(false) == KERN_SUCCESS)
+ return m_state.gpr.__sp;
+ return failValue;
+}
+
+kern_return_t
+DNBArchMachARM::GetGPRState(bool force)
+{
+ int set = e_regSetGPR;
+ // Check if we have valid cached registers
+ if (!force && m_state.GetError(set, Read) == KERN_SUCCESS)
+ return KERN_SUCCESS;
+
+ // Read the registers from our thread
+ mach_msg_type_number_t count = ARM_THREAD_STATE_COUNT;
+ kern_return_t kret = ::thread_get_state(m_thread->ThreadID(), ARM_THREAD_STATE, (thread_state_t)&m_state.gpr, &count);
+ uint32_t *r = &m_state.gpr.__r[0];
+ DNBLogThreadedIf(LOG_THREAD, "thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x regs r0=%8.8x r1=%8.8x r2=%8.8x r3=%8.8x r4=%8.8x r5=%8.8x r6=%8.8x r7=%8.8x r8=%8.8x r9=%8.8x r10=%8.8x r11=%8.8x s12=%8.8x sp=%8.8x lr=%8.8x pc=%8.8x cpsr=%8.8x", m_thread->ThreadID(), ARM_THREAD_STATE, ARM_THREAD_STATE_COUNT, kret,
+ r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15], r[16]);
+ m_state.SetError(set, Read, kret);
+ return kret;
+}
+
+kern_return_t
+DNBArchMachARM::GetVFPState(bool force)
+{
+ int set = e_regSetVFP;
+ // Check if we have valid cached registers
+ if (!force && m_state.GetError(set, Read) == KERN_SUCCESS)
+ return KERN_SUCCESS;
+
+ // Read the registers from our thread
+ mach_msg_type_number_t count = ARM_VFP_STATE_COUNT;
+ kern_return_t kret = ::thread_get_state(m_thread->ThreadID(), ARM_VFP_STATE, (thread_state_t)&m_state.vfp, &count);
+ m_state.SetError(set, Read, kret);
+ return kret;
+}
+
+kern_return_t
+DNBArchMachARM::GetEXCState(bool force)
+{
+ int set = e_regSetEXC;
+ // Check if we have valid cached registers
+ if (!force && m_state.GetError(set, Read) == KERN_SUCCESS)
+ return KERN_SUCCESS;
+
+ // Read the registers from our thread
+ mach_msg_type_number_t count = ARM_EXCEPTION_STATE_COUNT;
+ kern_return_t kret = ::thread_get_state(m_thread->ThreadID(), ARM_EXCEPTION_STATE, (thread_state_t)&m_state.exc, &count);
+ m_state.SetError(set, Read, kret);
+ return kret;
+}
+
+static void
+DumpDBGState(const arm_debug_state_t& dbg)
+{
+ uint32_t i = 0;
+ for (i=0; i<16; i++)
+ DNBLogThreadedIf(LOG_STEP, "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]);
+}
+
+kern_return_t
+DNBArchMachARM::GetDBGState(bool force)
+{
+ int set = e_regSetDBG;
+
+ // Check if we have valid cached registers
+ if (!force && m_state.GetError(set, Read) == KERN_SUCCESS)
+ return KERN_SUCCESS;
+
+ // Read the registers from our thread
+ mach_msg_type_number_t count = ARM_DEBUG_STATE_COUNT;
+ kern_return_t kret = ::thread_get_state(m_thread->ThreadID(), ARM_DEBUG_STATE, (thread_state_t)&m_state.dbg, &count);
+ m_state.SetError(set, Read, kret);
+ return kret;
+}
+
+kern_return_t
+DNBArchMachARM::SetGPRState()
+{
+ int set = e_regSetGPR;
+ kern_return_t kret = ::thread_set_state(m_thread->ThreadID(), ARM_THREAD_STATE, (thread_state_t)&m_state.gpr, ARM_THREAD_STATE_COUNT);
+ m_state.SetError(set, Write, kret); // Set the current write error for this register set
+ m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently
+ return kret; // Return the error code
+}
+
+kern_return_t
+DNBArchMachARM::SetVFPState()
+{
+ int set = e_regSetVFP;
+ kern_return_t kret = ::thread_set_state (m_thread->ThreadID(), ARM_VFP_STATE, (thread_state_t)&m_state.vfp, ARM_VFP_STATE_COUNT);
+ m_state.SetError(set, Write, kret); // Set the current write error for this register set
+ m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently
+ return kret; // Return the error code
+}
+
+kern_return_t
+DNBArchMachARM::SetEXCState()
+{
+ int set = e_regSetEXC;
+ kern_return_t kret = ::thread_set_state (m_thread->ThreadID(), ARM_EXCEPTION_STATE, (thread_state_t)&m_state.exc, ARM_EXCEPTION_STATE_COUNT);
+ m_state.SetError(set, Write, kret); // Set the current write error for this register set
+ m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently
+ return kret; // Return the error code
+}
+
+kern_return_t
+DNBArchMachARM::SetDBGState()
+{
+ int set = e_regSetDBG;
+ kern_return_t kret = ::thread_set_state (m_thread->ThreadID(), ARM_DEBUG_STATE, (thread_state_t)&m_state.dbg, ARM_DEBUG_STATE_COUNT);
+ m_state.SetError(set, Write, kret); // Set the current write error for this register set
+ m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently
+ return kret; // Return the error code
+}
+
+void
+DNBArchMachARM::ThreadWillResume()
+{
+ // Do we need to step this thread? If so, let the mach thread tell us so.
+ if (m_thread->IsStepping())
+ {
+ bool step_handled = false;
+ // This is the primary thread, let the arch do anything it needs
+ if (NumSupportedHardwareBreakpoints() > 0)
+ {
+#if defined (DNB_ARCH_MACH_ARM_DEBUG_SW_STEP)
+ bool half_step = m_hw_single_chained_step_addr != INVALID_NUB_ADDRESS;
+#endif
+ step_handled = EnableHardwareSingleStep(true) == KERN_SUCCESS;
+#if defined (DNB_ARCH_MACH_ARM_DEBUG_SW_STEP)
+ if (!half_step)
+ step_handled = false;
+#endif
+ }
+
+ if (!step_handled)
+ {
+ SetSingleStepSoftwareBreakpoints();
+ }
+ }
+}
+
+bool
+DNBArchMachARM::ThreadDidStop()
+{
+ bool success = true;
+
+ m_state.InvalidateRegisterSetState (e_regSetALL);
+
+ // Are we stepping a single instruction?
+ if (GetGPRState(true) == KERN_SUCCESS)
+ {
+ // We are single stepping, was this the primary thread?
+ if (m_thread->IsStepping())
+ {
+#if defined (DNB_ARCH_MACH_ARM_DEBUG_SW_STEP)
+ success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
+ // Hardware single step must work if we are going to test software
+ // single step functionality
+ assert(success);
+ if (m_hw_single_chained_step_addr == INVALID_NUB_ADDRESS && m_sw_single_step_next_pc != INVALID_NUB_ADDRESS)
+ {
+ uint32_t sw_step_next_pc = m_sw_single_step_next_pc & 0xFFFFFFFEu;
+ bool sw_step_next_pc_is_thumb = (m_sw_single_step_next_pc & 1) != 0;
+ bool actual_next_pc_is_thumb = (m_state.gpr.__cpsr & 0x20) != 0;
+ if (m_state.gpr.__pc != sw_step_next_pc)
+ {
+ DNBLogError("curr pc = 0x%8.8x - calculated single step target PC was incorrect: 0x%8.8x != 0x%8.8x", m_state.gpr.__pc, sw_step_next_pc, m_state.gpr.__pc);
+ exit(1);
+ }
+ if (actual_next_pc_is_thumb != sw_step_next_pc_is_thumb)
+ {
+ DNBLogError("curr pc = 0x%8.8x - calculated single step calculated mode mismatch: sw single mode = %s != %s",
+ m_state.gpr.__pc,
+ actual_next_pc_is_thumb ? "Thumb" : "ARM",
+ sw_step_next_pc_is_thumb ? "Thumb" : "ARM");
+ exit(1);
+ }
+ m_sw_single_step_next_pc = INVALID_NUB_ADDRESS;
+ }
+#else
+ // Are we software single stepping?
+ if (NUB_BREAK_ID_IS_VALID(m_sw_single_step_break_id) || m_sw_single_step_itblock_break_count)
+ {
+ // Remove any software single stepping breakpoints that we have set
+
+ // Do we have a normal software single step breakpoint?
+ if (NUB_BREAK_ID_IS_VALID(m_sw_single_step_break_id))
+ {
+ DNBLogThreadedIf(LOG_STEP, "%s: removing software single step breakpoint (breakID=%d)", __FUNCTION__, m_sw_single_step_break_id);
+ success = m_thread->Process()->DisableBreakpoint(m_sw_single_step_break_id, true);
+ m_sw_single_step_break_id = INVALID_NUB_BREAK_ID;
+ }
+
+ // Do we have any Thumb IT breakpoints?
+ if (m_sw_single_step_itblock_break_count > 0)
+ {
+ // See if we hit one of our Thumb IT breakpoints?
+ DNBBreakpoint *step_bp = m_thread->Process()->Breakpoints().FindByAddress(m_state.gpr.__pc);
+
+ if (step_bp)
+ {
+ // We did hit our breakpoint, tell the breakpoint it was
+ // hit so that it can run its callback routine and fixup
+ // the PC.
+ DNBLogThreadedIf(LOG_STEP, "%s: IT software single step breakpoint hit (breakID=%u)", __FUNCTION__, step_bp->GetID());
+ step_bp->BreakpointHit(m_thread->Process()->ProcessID(), m_thread->ThreadID());
+ }
+
+ // Remove all Thumb IT breakpoints
+ for (int i = 0; i < m_sw_single_step_itblock_break_count; i++)
+ {
+ if (NUB_BREAK_ID_IS_VALID(m_sw_single_step_itblock_break_id[i]))
+ {
+ DNBLogThreadedIf(LOG_STEP, "%s: removing IT software single step breakpoint (breakID=%d)", __FUNCTION__, m_sw_single_step_itblock_break_id[i]);
+ success = m_thread->Process()->DisableBreakpoint(m_sw_single_step_itblock_break_id[i], true);
+ m_sw_single_step_itblock_break_id[i] = INVALID_NUB_BREAK_ID;
+ }
+ }
+ m_sw_single_step_itblock_break_count = 0;
+
+ // Decode instructions up to the current PC to ensure the internal decoder state is valid for the IT block
+ // The decoder has to decode each instruction in the IT block even if it is not executed so that
+ // the fields are correctly updated
+ DecodeITBlockInstructions(m_state.gpr.__pc);
+ }
+
+ }
+ else
+ success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
+#endif
+ }
+ else
+ {
+ // The MachThread will automatically restore the suspend count
+ // in ThreadDidStop(), so we don't need to do anything here if
+ // we weren't the primary thread the last time
+ }
+ }
+ return success;
+}
+
+bool
+DNBArchMachARM::StepNotComplete ()
+{
+ if (m_hw_single_chained_step_addr != INVALID_NUB_ADDRESS)
+ {
+ kern_return_t kret = KERN_INVALID_ARGUMENT;
+ kret = GetGPRState(false);
+ if (kret == KERN_SUCCESS)
+ {
+ if (m_state.gpr.__pc == m_hw_single_chained_step_addr)
+ {
+ DNBLogThreadedIf(LOG_STEP, "Need to step some more at 0x%8.8x", m_hw_single_chained_step_addr);
+ return true;
+ }
+ }
+ }
+
+ m_hw_single_chained_step_addr = INVALID_NUB_ADDRESS;
+ return false;
+}
+
+
+void
+DNBArchMachARM::DecodeITBlockInstructions(nub_addr_t curr_pc)
+
+{
+ uint16_t opcode16;
+ uint32_t opcode32;
+ nub_addr_t next_pc_in_itblock;
+ nub_addr_t pc_in_itblock = m_last_decode_pc;
+
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: last_decode_pc=0x%8.8x", __FUNCTION__, m_last_decode_pc);
+
+ // Decode IT block instruction from the instruction following the m_last_decoded_instruction at
+ // PC m_last_decode_pc upto and including the instruction at curr_pc
+ if (m_thread->Process()->Task().ReadMemory(pc_in_itblock, 2, &opcode16) == 2)
+ {
+ opcode32 = opcode16;
+ pc_in_itblock += 2;
+ // Check for 32 bit thumb opcode and read the upper 16 bits if needed
+ if (((opcode32 & 0xE000) == 0xE000) && opcode32 & 0x1800)
+ {
+ // Adjust 'next_pc_in_itblock' to point to the default next Thumb instruction for
+ // a 32 bit Thumb opcode
+ // Read bits 31:16 of a 32 bit Thumb opcode
+ if (m_thread->Process()->Task().ReadMemory(pc_in_itblock, 2, &opcode16) == 2)
+ {
+ pc_in_itblock += 2;
+ // 32 bit thumb opcode
+ opcode32 = (opcode32 << 16) | opcode16;
+ }
+ else
+ {
+ DNBLogError("%s: Unable to read opcode bits 31:16 for a 32 bit thumb opcode at pc=0x%8.8lx", __FUNCTION__, pc_in_itblock);
+ }
+ }
+ }
+ else
+ {
+ DNBLogError("%s: Error reading 16-bit Thumb instruction at pc=0x%8.8x", __FUNCTION__, pc_in_itblock);
+ }
+
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: pc_in_itblock=0x%8.8x, curr_pc=0x%8.8x", __FUNCTION__, pc_in_itblock, curr_pc);
+
+ next_pc_in_itblock = pc_in_itblock;
+ while (next_pc_in_itblock <= curr_pc)
+ {
+ arm_error_t decodeError;
+
+ m_last_decode_pc = pc_in_itblock;
+ decodeError = DecodeInstructionUsingDisassembler(pc_in_itblock, m_state.gpr.__cpsr, &m_last_decode_arm, &m_last_decode_thumb, &next_pc_in_itblock);
+
+ pc_in_itblock = next_pc_in_itblock;
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: next_pc_in_itblock=0x%8.8x", __FUNCTION__, next_pc_in_itblock);
+ }
+}
+
+
+// Set the single step bit in the processor status register.
+kern_return_t
+DNBArchMachARM::EnableHardwareSingleStep (bool enable)
+{
+ DNBError err;
+ DNBLogThreadedIf(LOG_STEP, "%s( enable = %d )", __FUNCTION__, enable);
+
+ err = GetGPRState(false);
+
+ if (err.Fail())
+ {
+ err.LogThreaded("%s: failed to read the GPR registers", __FUNCTION__);
+ return err.Error();
+ }
+
+ err = GetDBGState(false);
+
+ if (err.Fail())
+ {
+ err.LogThreaded("%s: failed to read the DBG registers", __FUNCTION__);
+ return err.Error();
+ }
+
+ const uint32_t i = 0;
+ if (enable)
+ {
+ m_hw_single_chained_step_addr = INVALID_NUB_ADDRESS;
+
+ // Save our previous state
+ m_dbg_save = m_state.dbg;
+ // Set a breakpoint that will stop when the PC doesn't match the current one!
+ m_state.dbg.__bvr[i] = m_state.gpr.__pc & 0xFFFFFFFCu; // Set the current PC as the breakpoint address
+ m_state.dbg.__bcr[i] = BCR_M_IMVA_MISMATCH | // Stop on address mismatch
+ S_USER | // Stop only in user mode
+ BCR_ENABLE; // Enable this breakpoint
+ if (m_state.gpr.__cpsr & 0x20)
+ {
+ // Thumb breakpoint
+ if (m_state.gpr.__pc & 2)
+ m_state.dbg.__bcr[i] |= BAS_IMVA_2_3;
+ else
+ m_state.dbg.__bcr[i] |= BAS_IMVA_0_1;
+
+ uint16_t opcode;
+ if (sizeof(opcode) == m_thread->Process()->Task().ReadMemory(m_state.gpr.__pc, sizeof(opcode), &opcode))
+ {
+ if (((opcode & 0xE000) == 0xE000) && opcode & 0x1800)
+ {
+ // 32 bit thumb opcode...
+ if (m_state.gpr.__pc & 2)
+ {
+ // We can't take care of a 32 bit thumb instruction single step
+ // with just IVA mismatching. We will need to chain an extra
+ // hardware single step in order to complete this single step...
+ m_hw_single_chained_step_addr = m_state.gpr.__pc + 2;
+ }
+ else
+ {
+ // Extend the number of bits to ignore for the mismatch
+ m_state.dbg.__bcr[i] |= BAS_IMVA_ALL;
+ }
+ }
+ }
+ }
+ else
+ {
+ // ARM breakpoint
+ m_state.dbg.__bcr[i] |= BAS_IMVA_ALL; // Stop when any address bits change
+ }
+
+ DNBLogThreadedIf(LOG_STEP, "%s: BVR%u=0x%8.8x BCR%u=0x%8.8x", __FUNCTION__, i, m_state.dbg.__bvr[i], i, m_state.dbg.__bcr[i]);
+
+ for (uint32_t j=i+1; j<16; ++j)
+ {
+ // Disable all others
+ m_state.dbg.__bvr[j] = 0;
+ m_state.dbg.__bcr[j] = 0;
+ }
+ }
+ else
+ {
+ // Just restore the state we had before we did single stepping
+ m_state.dbg = m_dbg_save;
+ }
+
+ return SetDBGState();
+}
+
+// return 1 if bit "BIT" is set in "value"
+static inline uint32_t bit(uint32_t value, uint32_t bit)
+{
+ return (value >> bit) & 1u;
+}
+
+// return the bitfield "value[msbit:lsbit]".
+static inline uint32_t bits(uint32_t value, uint32_t msbit, uint32_t lsbit)
+{
+ assert(msbit >= lsbit);
+ uint32_t shift_left = sizeof(value) * 8 - 1 - msbit;
+ value <<= shift_left; // shift anything above the msbit off of the unsigned edge
+ value >>= shift_left + lsbit; // shift it back again down to the lsbit (including undoing any shift from above)
+ return value; // return our result
+}
+
+bool
+DNBArchMachARM::ConditionPassed(uint8_t condition, uint32_t cpsr)
+{
+ uint32_t cpsr_n = bit(cpsr, 31); // Negative condition code flag
+ uint32_t cpsr_z = bit(cpsr, 30); // Zero condition code flag
+ uint32_t cpsr_c = bit(cpsr, 29); // Carry condition code flag
+ uint32_t cpsr_v = bit(cpsr, 28); // Overflow condition code flag
+
+ switch (condition) {
+ case COND_EQ: // (0x0)
+ if (cpsr_z == 1) return true;
+ break;
+ case COND_NE: // (0x1)
+ if (cpsr_z == 0) return true;
+ break;
+ case COND_CS: // (0x2)
+ if (cpsr_c == 1) return true;
+ break;
+ case COND_CC: // (0x3)
+ if (cpsr_c == 0) return true;
+ break;
+ case COND_MI: // (0x4)
+ if (cpsr_n == 1) return true;
+ break;
+ case COND_PL: // (0x5)
+ if (cpsr_n == 0) return true;
+ break;
+ case COND_VS: // (0x6)
+ if (cpsr_v == 1) return true;
+ break;
+ case COND_VC: // (0x7)
+ if (cpsr_v == 0) return true;
+ break;
+ case COND_HI: // (0x8)
+ if ((cpsr_c == 1) && (cpsr_z == 0)) return true;
+ break;
+ case COND_LS: // (0x9)
+ if ((cpsr_c == 0) || (cpsr_z == 1)) return true;
+ break;
+ case COND_GE: // (0xA)
+ if (cpsr_n == cpsr_v) return true;
+ break;
+ case COND_LT: // (0xB)
+ if (cpsr_n != cpsr_v) return true;
+ break;
+ case COND_GT: // (0xC)
+ if ((cpsr_z == 0) && (cpsr_n == cpsr_v)) return true;
+ break;
+ case COND_LE: // (0xD)
+ if ((cpsr_z == 1) || (cpsr_n != cpsr_v)) return true;
+ break;
+ default:
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+bool
+DNBArchMachARM::ComputeNextPC(nub_addr_t currentPC, arm_decoded_instruction_t decodedInstruction, bool currentPCIsThumb, nub_addr_t *targetPC)
+{
+ nub_addr_t myTargetPC, addressWherePCLives;
+ pid_t mypid;
+
+ uint32_t cpsr_c = bit(m_state.gpr.__cpsr, 29); // Carry condition code flag
+
+ uint32_t firstOperand=0, secondOperand=0, shiftAmount=0, secondOperandAfterShift=0, immediateValue=0;
+ uint32_t halfwords=0, baseAddress=0, immediateOffset=0, addressOffsetFromRegister=0, addressOffsetFromRegisterAfterShift;
+ uint32_t baseAddressIndex=INVALID_NUB_HW_INDEX;
+ uint32_t firstOperandIndex=INVALID_NUB_HW_INDEX;
+ uint32_t secondOperandIndex=INVALID_NUB_HW_INDEX;
+ uint32_t addressOffsetFromRegisterIndex=INVALID_NUB_HW_INDEX;
+ uint32_t shiftRegisterIndex=INVALID_NUB_HW_INDEX;
+ uint16_t registerList16, registerList16NoPC;
+ uint8_t registerList8;
+ uint32_t numRegistersToLoad=0;
+
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: instruction->code=%d", __FUNCTION__, decodedInstruction.instruction->code);
+
+ // Get the following in this switch statement:
+ // - firstOperand, secondOperand, immediateValue, shiftAmount: For arithmetic, logical and move instructions
+ // - baseAddress, immediateOffset, shiftAmount: For LDR
+ // - numRegistersToLoad: For LDM and POP instructions
+ switch (decodedInstruction.instruction->code)
+ {
+ // Arithmetic operations that can change the PC
+ case ARM_INST_ADC:
+ case ARM_INST_ADCS:
+ case ARM_INST_ADD:
+ case ARM_INST_ADDS:
+ case ARM_INST_AND:
+ case ARM_INST_ANDS:
+ case ARM_INST_ASR:
+ case ARM_INST_ASRS:
+ case ARM_INST_BIC:
+ case ARM_INST_BICS:
+ case ARM_INST_EOR:
+ case ARM_INST_EORS:
+ case ARM_INST_ORR:
+ case ARM_INST_ORRS:
+ case ARM_INST_RSB:
+ case ARM_INST_RSBS:
+ case ARM_INST_RSC:
+ case ARM_INST_RSCS:
+ case ARM_INST_SBC:
+ case ARM_INST_SBCS:
+ case ARM_INST_SUB:
+ case ARM_INST_SUBS:
+ switch (decodedInstruction.addressMode)
+ {
+ case ARM_ADDR_DATA_IMM:
+ if (decodedInstruction.numOperands != 3)
+ {
+ DNBLogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=1)
+ firstOperandIndex = decodedInstruction.op[1].value; // first operand register index
+ firstOperand = m_state.gpr.__r[firstOperandIndex];
+
+ // Get immediateValue (at index=2)
+ immediateValue = decodedInstruction.op[2].value;
+
+ break;
+
+ case ARM_ADDR_DATA_REG:
+ if (decodedInstruction.numOperands != 3)
+ {
+ DNBLogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=1)
+ firstOperandIndex = decodedInstruction.op[1].value; // first operand register index
+ firstOperand = m_state.gpr.__r[firstOperandIndex];
+
+ // Get secondOperand register value (at index=2)
+ secondOperandIndex = decodedInstruction.op[2].value; // second operand register index
+ secondOperand = m_state.gpr.__r[secondOperandIndex];
+
+ break;
+
+ case ARM_ADDR_DATA_SCALED_IMM:
+ if (decodedInstruction.numOperands != 4)
+ {
+ DNBLogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=1)
+ firstOperandIndex = decodedInstruction.op[1].value; // first operand register index
+ firstOperand = m_state.gpr.__r[firstOperandIndex];
+
+ // Get secondOperand register value (at index=2)
+ secondOperandIndex = decodedInstruction.op[2].value; // second operand register index
+ secondOperand = m_state.gpr.__r[secondOperandIndex];
+
+ // Get shiftAmount as immediate value (at index=3)
+ shiftAmount = decodedInstruction.op[3].value;
+
+ break;
+
+
+ case ARM_ADDR_DATA_SCALED_REG:
+ if (decodedInstruction.numOperands != 4)
+ {
+ DNBLogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=1)
+ firstOperandIndex = decodedInstruction.op[1].value; // first operand register index
+ firstOperand = m_state.gpr.__r[firstOperandIndex];
+
+ // Get secondOperand register value (at index=2)
+ secondOperandIndex = decodedInstruction.op[2].value; // second operand register index
+ secondOperand = m_state.gpr.__r[secondOperandIndex];
+
+ // Get shiftAmount from register (at index=3)
+ shiftRegisterIndex = decodedInstruction.op[3].value; // second operand register index
+ shiftAmount = m_state.gpr.__r[shiftRegisterIndex];
+
+ break;
+
+ case THUMB_ADDR_HR_HR:
+ if (decodedInstruction.numOperands != 2)
+ {
+ DNBLogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get firstOperand register value (at index=0)
+ firstOperandIndex = decodedInstruction.op[0].value; // first operand register index
+ firstOperand = m_state.gpr.__r[firstOperandIndex];
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[1].value; // second operand register index
+ secondOperand = m_state.gpr.__r[secondOperandIndex];
+
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ // Logical shifts and move operations that can change the PC
+ case ARM_INST_LSL:
+ case ARM_INST_LSLS:
+ case ARM_INST_LSR:
+ case ARM_INST_LSRS:
+ case ARM_INST_MOV:
+ case ARM_INST_MOVS:
+ case ARM_INST_MVN:
+ case ARM_INST_MVNS:
+ case ARM_INST_ROR:
+ case ARM_INST_RORS:
+ case ARM_INST_RRX:
+ case ARM_INST_RRXS:
+ // In these cases, the firstOperand is always 0, as if it does not exist
+ switch (decodedInstruction.addressMode)
+ {
+ case ARM_ADDR_DATA_IMM:
+ if (decodedInstruction.numOperands != 2)
+ {
+ DNBLogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get immediateValue (at index=1)
+ immediateValue = decodedInstruction.op[1].value;
+
+ break;
+
+ case ARM_ADDR_DATA_REG:
+ if (decodedInstruction.numOperands != 2)
+ {
+ DNBLogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[1].value; // second operand register index
+ secondOperand = m_state.gpr.__r[secondOperandIndex];
+
+ break;
+
+ case ARM_ADDR_DATA_SCALED_IMM:
+ if (decodedInstruction.numOperands != 3)
+ {
+ DNBLogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[2].value; // second operand register index
+ secondOperand = m_state.gpr.__r[secondOperandIndex];
+
+ // Get shiftAmount as immediate value (at index=2)
+ shiftAmount = decodedInstruction.op[2].value;
+
+ break;
+
+
+ case ARM_ADDR_DATA_SCALED_REG:
+ if (decodedInstruction.numOperands != 3)
+ {
+ DNBLogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[1].value; // second operand register index
+ secondOperand = m_state.gpr.__r[secondOperandIndex];
+
+ // Get shiftAmount from register (at index=2)
+ shiftRegisterIndex = decodedInstruction.op[2].value; // second operand register index
+ shiftAmount = m_state.gpr.__r[shiftRegisterIndex];
+
+ break;
+
+ case THUMB_ADDR_HR_HR:
+ if (decodedInstruction.numOperands != 2)
+ {
+ DNBLogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ if (decodedInstruction.op[0].value != PC_REG)
+ {
+ DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+
+ // Get secondOperand register value (at index=1)
+ secondOperandIndex = decodedInstruction.op[1].value; // second operand register index
+ secondOperand = m_state.gpr.__r[secondOperandIndex];
+
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ // Simple branches, used to hop around within a routine
+ case ARM_INST_B:
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ break;
+
+ // Branch-and-link, used to call ARM subroutines
+ case ARM_INST_BL:
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ break;
+
+ // Branch-and-link with exchange, used to call opposite-mode subroutines
+ case ARM_INST_BLX:
+ if ((decodedInstruction.addressMode == ARM_ADDR_BRANCH_IMM) ||
+ (decodedInstruction.addressMode == THUMB_ADDR_UNCOND))
+ {
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ }
+ else // addressMode == ARM_ADDR_BRANCH_REG
+ {
+ // Unknown target unless we're branching to the PC itself,
+ // although this may not work properly with BLX
+ if (decodedInstruction.op[REG_RD].value == PC_REG)
+ {
+ // this should (almost) never happen
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ }
+
+ // Get the branch address and return
+ if (decodedInstruction.numOperands != 1)
+ {
+ DNBLogError("Expected 1 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get branch address in register (at index=0)
+ *targetPC = m_state.gpr.__r[decodedInstruction.op[0].value];
+ return true;
+ }
+ break;
+
+ // Branch with exchange, used to hop to opposite-mode code
+ // Branch to Jazelle code, used to execute Java; included here since it
+ // acts just like BX unless the Jazelle unit is active and JPC is
+ // already loaded into it.
+ case ARM_INST_BX:
+ case ARM_INST_BXJ:
+ // Unknown target unless we're branching to the PC itself,
+ // although this can never switch to Thumb mode and is
+ // therefore pretty much useless
+ if (decodedInstruction.op[REG_RD].value == PC_REG)
+ {
+ // this should (almost) never happen
+ *targetPC = decodedInstruction.targetPC; // Known targetPC
+ return true;
+ }
+
+ // Get the branch address and return
+ if (decodedInstruction.numOperands != 1)
+ {
+ DNBLogError("Expected 1 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get branch address in register (at index=0)
+ *targetPC = m_state.gpr.__r[decodedInstruction.op[0].value];
+ return true;
+ break;
+
+ // Compare and branch on zero/non-zero (Thumb-16 only)
+ // Unusual condition check built into the instruction
+ case ARM_INST_CBZ:
+ case ARM_INST_CBNZ:
+ // Branch address is known at compile time
+ // Get the branch address and return
+ if (decodedInstruction.numOperands != 2)
+ {
+ DNBLogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get branch address as an immediate value (at index=1)
+ *targetPC = decodedInstruction.op[1].value;
+ return true;
+ break;
+
+ // Load register can be used to load PC, usually with a function pointer
+ case ARM_INST_LDR:
+ if (decodedInstruction.op[REG_RD].value != PC_REG)
+ {
+ DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+ switch (decodedInstruction.addressMode)
+ {
+ case ARM_ADDR_LSWUB_IMM:
+ case ARM_ADDR_LSWUB_IMM_PRE:
+ case ARM_ADDR_LSWUB_IMM_POST:
+ if (decodedInstruction.numOperands != 3)
+ {
+ DNBLogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get baseAddress from register (at index=1)
+ baseAddressIndex = decodedInstruction.op[1].value;
+ baseAddress = m_state.gpr.__r[baseAddressIndex];
+
+ // Get immediateOffset (at index=2)
+ immediateOffset = decodedInstruction.op[2].value;
+ break;
+
+ case ARM_ADDR_LSWUB_REG:
+ case ARM_ADDR_LSWUB_REG_PRE:
+ case ARM_ADDR_LSWUB_REG_POST:
+ if (decodedInstruction.numOperands != 3)
+ {
+ DNBLogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get baseAddress from register (at index=1)
+ baseAddressIndex = decodedInstruction.op[1].value;
+ baseAddress = m_state.gpr.__r[baseAddressIndex];
+
+ // Get immediateOffset from register (at index=2)
+ addressOffsetFromRegisterIndex = decodedInstruction.op[2].value;
+ addressOffsetFromRegister = m_state.gpr.__r[addressOffsetFromRegisterIndex];
+
+ break;
+
+ case ARM_ADDR_LSWUB_SCALED:
+ case ARM_ADDR_LSWUB_SCALED_PRE:
+ case ARM_ADDR_LSWUB_SCALED_POST:
+ if (decodedInstruction.numOperands != 4)
+ {
+ DNBLogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get baseAddress from register (at index=1)
+ baseAddressIndex = decodedInstruction.op[1].value;
+ baseAddress = m_state.gpr.__r[baseAddressIndex];
+
+ // Get immediateOffset from register (at index=2)
+ addressOffsetFromRegisterIndex = decodedInstruction.op[2].value;
+ addressOffsetFromRegister = m_state.gpr.__r[addressOffsetFromRegisterIndex];
+
+ // Get shiftAmount (at index=3)
+ shiftAmount = decodedInstruction.op[3].value;
+
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ // 32b load multiple operations can load the PC along with everything else,
+ // usually to return from a function call
+ case ARM_INST_LDMDA:
+ case ARM_INST_LDMDB:
+ case ARM_INST_LDMIA:
+ case ARM_INST_LDMIB:
+ if (decodedInstruction.op[LDM_REGLIST].value & PC_REGLIST_BIT)
+ {
+ if (decodedInstruction.numOperands != 2)
+ {
+ DNBLogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands);
+ return false;
+ }
+
+ // Get baseAddress from register (at index=0)
+ baseAddressIndex = decodedInstruction.op[0].value;
+ baseAddress = m_state.gpr.__r[baseAddressIndex];
+
+ // Get registerList from register (at index=1)
+ registerList16 = (uint16_t)decodedInstruction.op[1].value;
+
+ // Count number of registers to load in the multiple register list excluding the PC
+ registerList16NoPC = registerList16&0x3FFF; // exclude the PC
+ numRegistersToLoad=0;
+ for (int i = 0; i < 16; i++)
+ {
+ if (registerList16NoPC & 0x1) numRegistersToLoad++;
+ registerList16NoPC = registerList16NoPC >> 1;
+ }
+ }
+ else
+ {
+ DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value);
+ return false;
+ }
+ break;
+
+ // Normal 16-bit LD multiple can't touch R15, but POP can
+ case ARM_INST_POP: // Can also get the PC & updates SP
+ // Get baseAddress from SP (at index=0)
+ baseAddress = m_state.gpr.__sp;
+
+ if (decodedInstruction.thumb16b)
+ {
+ // Get registerList from register (at index=0)
+ registerList8 = (uint8_t)decodedInstruction.op[0].value;
+
+ // Count number of registers to load in the multiple register list
+ numRegistersToLoad=0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (registerList8 & 0x1) numRegistersToLoad++;
+ registerList8 = registerList8 >> 1;
+ }
+ }
+ else
+ {
+ // Get registerList from register (at index=0)
+ registerList16 = (uint16_t)decodedInstruction.op[0].value;
+
+ // Count number of registers to load in the multiple register list excluding the PC
+ registerList16NoPC = registerList16&0x3FFF; // exclude the PC
+ numRegistersToLoad=0;
+ for (int i = 0; i < 16; i++)
+ {
+ if (registerList16NoPC & 0x1) numRegistersToLoad++;
+ registerList16NoPC = registerList16NoPC >> 1;
+ }
+ }
+ break;
+
+ // 16b TBB and TBH instructions load a jump address from a table
+ case ARM_INST_TBB:
+ case ARM_INST_TBH:
+ // Get baseAddress from register (at index=0)
+ baseAddressIndex = decodedInstruction.op[0].value;
+ baseAddress = m_state.gpr.__r[baseAddressIndex];
+
+ // Get immediateOffset from register (at index=1)
+ addressOffsetFromRegisterIndex = decodedInstruction.op[1].value;
+ addressOffsetFromRegister = m_state.gpr.__r[addressOffsetFromRegisterIndex];
+ break;
+
+ // ThumbEE branch-to-handler instructions: Jump to handlers at some offset
+ // from a special base pointer register (which is unknown at disassembly time)
+ case ARM_INST_HB:
+ case ARM_INST_HBP:
+// TODO: ARM_INST_HB, ARM_INST_HBP
+ break;
+
+ case ARM_INST_HBL:
+ case ARM_INST_HBLP:
+// TODO: ARM_INST_HBL, ARM_INST_HBLP
+ break;
+
+ // Breakpoint and software interrupt jump to interrupt handler (always ARM)
+ case ARM_INST_BKPT:
+ case ARM_INST_SMC:
+ case ARM_INST_SVC:
+
+ // Return from exception, obviously modifies PC [interrupt only!]
+ case ARM_INST_RFEDA:
+ case ARM_INST_RFEDB:
+ case ARM_INST_RFEIA:
+ case ARM_INST_RFEIB:
+
+ // Other instructions either can't change R15 or are "undefined" if you do,
+ // so no sane compiler should ever generate them & we don't care here.
+ // Also, R15 can only legally be used in a read-only manner for the
+ // various ARM addressing mode (to get PC-relative addressing of constants),
+ // but can NOT be used with any of the update modes.
+ default:
+ DNBLogError("%s should not be called for instruction code %d!", __FUNCTION__, decodedInstruction.instruction->code);
+ return false;
+ break;
+ }
+
+ // Adjust PC if PC is one of the input operands
+ if (baseAddressIndex == PC_REG)
+ {
+ if (currentPCIsThumb)
+ baseAddress += 4;
+ else
+ baseAddress += 8;
+ }
+
+ if (firstOperandIndex == PC_REG)
+ {
+ if (currentPCIsThumb)
+ firstOperand += 4;
+ else
+ firstOperand += 8;
+ }
+
+ if (secondOperandIndex == PC_REG)
+ {
+ if (currentPCIsThumb)
+ secondOperand += 4;
+ else
+ secondOperand += 8;
+ }
+
+ if (addressOffsetFromRegisterIndex == PC_REG)
+ {
+ if (currentPCIsThumb)
+ addressOffsetFromRegister += 4;
+ else
+ addressOffsetFromRegister += 8;
+ }
+
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE,
+ "%s: firstOperand=%8.8x, secondOperand=%8.8x, immediateValue = %d, shiftAmount = %d, baseAddress = %8.8x, addressOffsetFromRegister = %8.8x, immediateOffset = %d, numRegistersToLoad = %d",
+ __FUNCTION__,
+ firstOperand,
+ secondOperand,
+ immediateValue,
+ shiftAmount,
+ baseAddress,
+ addressOffsetFromRegister,
+ immediateOffset,
+ numRegistersToLoad);
+
+
+ // Calculate following values after applying shiftAmount:
+ // - immediateOffsetAfterShift, secondOperandAfterShift
+
+ switch (decodedInstruction.scaleMode)
+ {
+ case ARM_SCALE_NONE:
+ addressOffsetFromRegisterAfterShift = addressOffsetFromRegister;
+ secondOperandAfterShift = secondOperand;
+ break;
+
+ case ARM_SCALE_LSL: // Logical shift left
+ addressOffsetFromRegisterAfterShift = addressOffsetFromRegister << shiftAmount;
+ secondOperandAfterShift = secondOperand << shiftAmount;
+ break;
+
+ case ARM_SCALE_LSR: // Logical shift right
+ addressOffsetFromRegisterAfterShift = addressOffsetFromRegister >> shiftAmount;
+ secondOperandAfterShift = secondOperand >> shiftAmount;
+ break;
+
+ case ARM_SCALE_ASR: // Arithmetic shift right
+ asm("mov %0, %1, asr %2" : "=r" (addressOffsetFromRegisterAfterShift) : "r" (addressOffsetFromRegister), "r" (shiftAmount));
+ asm("mov %0, %1, asr %2" : "=r" (secondOperandAfterShift) : "r" (secondOperand), "r" (shiftAmount));
+ break;
+
+ case ARM_SCALE_ROR: // Rotate right
+ asm("mov %0, %1, ror %2" : "=r" (addressOffsetFromRegisterAfterShift) : "r" (addressOffsetFromRegister), "r" (shiftAmount));
+ asm("mov %0, %1, ror %2" : "=r" (secondOperandAfterShift) : "r" (secondOperand), "r" (shiftAmount));
+ break;
+
+ case ARM_SCALE_RRX: // Rotate right, pulling in carry (1-bit shift only)
+ asm("mov %0, %1, rrx" : "=r" (addressOffsetFromRegisterAfterShift) : "r" (addressOffsetFromRegister));
+ asm("mov %0, %1, rrx" : "=r" (secondOperandAfterShift) : "r" (secondOperand));
+ break;
+ }
+
+ // Emulate instruction to calculate targetPC
+ // All branches are already handled in the first switch statement. A branch should not reach this switch
+ switch (decodedInstruction.instruction->code)
+ {
+ // Arithmetic operations that can change the PC
+ case ARM_INST_ADC:
+ case ARM_INST_ADCS:
+ // Add with Carry
+ *targetPC = firstOperand + (secondOperandAfterShift + immediateValue) + cpsr_c;
+ break;
+
+ case ARM_INST_ADD:
+ case ARM_INST_ADDS:
+ *targetPC = firstOperand + (secondOperandAfterShift + immediateValue);
+ break;
+
+ case ARM_INST_AND:
+ case ARM_INST_ANDS:
+ *targetPC = firstOperand & (secondOperandAfterShift + immediateValue);
+ break;
+
+ case ARM_INST_ASR:
+ case ARM_INST_ASRS:
+ asm("mov %0, %1, asr %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_BIC:
+ case ARM_INST_BICS:
+ asm("bic %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_EOR:
+ case ARM_INST_EORS:
+ asm("eor %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_ORR:
+ case ARM_INST_ORRS:
+ asm("orr %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_RSB:
+ case ARM_INST_RSBS:
+ asm("rsb %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_RSC:
+ case ARM_INST_RSCS:
+ myTargetPC = secondOperandAfterShift - (firstOperand + !cpsr_c);
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_SBC:
+ case ARM_INST_SBCS:
+ asm("sbc %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue + !cpsr_c));
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_SUB:
+ case ARM_INST_SUBS:
+ asm("sub %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue));
+ *targetPC = myTargetPC;
+ break;
+
+ // Logical shifts and move operations that can change the PC
+ case ARM_INST_LSL:
+ case ARM_INST_LSLS:
+ case ARM_INST_LSR:
+ case ARM_INST_LSRS:
+ case ARM_INST_MOV:
+ case ARM_INST_MOVS:
+ case ARM_INST_ROR:
+ case ARM_INST_RORS:
+ case ARM_INST_RRX:
+ case ARM_INST_RRXS:
+ myTargetPC = secondOperandAfterShift + immediateValue;
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_MVN:
+ case ARM_INST_MVNS:
+ myTargetPC = !(secondOperandAfterShift + immediateValue);
+ *targetPC = myTargetPC;
+ break;
+
+ // Load register can be used to load PC, usually with a function pointer
+ case ARM_INST_LDR:
+ switch (decodedInstruction.addressMode) {
+ case ARM_ADDR_LSWUB_IMM_POST:
+ case ARM_ADDR_LSWUB_REG_POST:
+ case ARM_ADDR_LSWUB_SCALED_POST:
+ addressWherePCLives = baseAddress;
+ break;
+
+ case ARM_ADDR_LSWUB_IMM:
+ case ARM_ADDR_LSWUB_REG:
+ case ARM_ADDR_LSWUB_SCALED:
+ case ARM_ADDR_LSWUB_IMM_PRE:
+ case ARM_ADDR_LSWUB_REG_PRE:
+ case ARM_ADDR_LSWUB_SCALED_PRE:
+ addressWherePCLives = baseAddress + (addressOffsetFromRegisterAfterShift + immediateOffset);
+ break;
+
+ default:
+ break;
+ }
+
+ mypid = m_thread->ProcessID();
+ if (DNBProcessMemoryRead(mypid, addressWherePCLives, sizeof(nub_addr_t), &myTargetPC) != sizeof(nub_addr_t))
+ {
+ DNBLogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ // 32b load multiple operations can load the PC along with everything else,
+ // usually to return from a function call
+ case ARM_INST_LDMDA:
+ mypid = m_thread->ProcessID();
+ addressWherePCLives = baseAddress;
+ if (DNBProcessMemoryRead(mypid, addressWherePCLives, sizeof(nub_addr_t), &myTargetPC) != sizeof(nub_addr_t))
+ {
+ DNBLogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_LDMDB:
+ mypid = m_thread->ProcessID();
+ addressWherePCLives = baseAddress - 4;
+ if (DNBProcessMemoryRead(mypid, addressWherePCLives, sizeof(nub_addr_t), &myTargetPC) != sizeof(nub_addr_t))
+ {
+ DNBLogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_LDMIB:
+ mypid = m_thread->ProcessID();
+ addressWherePCLives = baseAddress + numRegistersToLoad*4 + 4;
+ if (DNBProcessMemoryRead(mypid, addressWherePCLives, sizeof(nub_addr_t), &myTargetPC) != sizeof(nub_addr_t))
+ {
+ DNBLogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ case ARM_INST_LDMIA: // same as pop
+ // Normal 16-bit LD multiple can't touch R15, but POP can
+ case ARM_INST_POP: // Can also get the PC & updates SP
+ mypid = m_thread->ProcessID();
+ addressWherePCLives = baseAddress + numRegistersToLoad*4;
+ if (DNBProcessMemoryRead(mypid, addressWherePCLives, sizeof(nub_addr_t), &myTargetPC) != sizeof(nub_addr_t))
+ {
+ DNBLogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives);
+ return false;
+ }
+
+ *targetPC = myTargetPC;
+ break;
+
+ // 16b TBB and TBH instructions load a jump address from a table
+ case ARM_INST_TBB:
+ mypid = m_thread->ProcessID();
+ addressWherePCLives = baseAddress + addressOffsetFromRegisterAfterShift;
+ if (DNBProcessMemoryRead(mypid, addressWherePCLives, 1, &halfwords) != 1)
+ {
+ DNBLogError("Could not read memory at %8.8x to get targetPC when processing the TBB instruction!", addressWherePCLives);
+ return false;
+ }
+ // add 4 to currentPC since we are in Thumb mode and then add 2*halfwords
+ *targetPC = (currentPC + 4) + 2*halfwords;
+ break;
+
+ case ARM_INST_TBH:
+ mypid = m_thread->ProcessID();
+ addressWherePCLives = ((baseAddress + (addressOffsetFromRegisterAfterShift << 1)) & ~0x1);
+ if (DNBProcessMemoryRead(mypid, addressWherePCLives, 2, &halfwords) != 2)
+ {
+ DNBLogError("Could not read memory at %8.8x to get targetPC when processing the TBH instruction!", addressWherePCLives);
+ return false;
+ }
+ // add 4 to currentPC since we are in Thumb mode and then add 2*halfwords
+ *targetPC = (currentPC + 4) + 2*halfwords;
+ break;
+
+ // ThumbEE branch-to-handler instructions: Jump to handlers at some offset
+ // from a special base pointer register (which is unknown at disassembly time)
+ case ARM_INST_HB:
+ case ARM_INST_HBP:
+ // TODO: ARM_INST_HB, ARM_INST_HBP
+ break;
+
+ case ARM_INST_HBL:
+ case ARM_INST_HBLP:
+ // TODO: ARM_INST_HBL, ARM_INST_HBLP
+ break;
+
+ // Breakpoint and software interrupt jump to interrupt handler (always ARM)
+ case ARM_INST_BKPT:
+ case ARM_INST_SMC:
+ case ARM_INST_SVC:
+ // TODO: ARM_INST_BKPT, ARM_INST_SMC, ARM_INST_SVC
+ break;
+
+ // Return from exception, obviously modifies PC [interrupt only!]
+ case ARM_INST_RFEDA:
+ case ARM_INST_RFEDB:
+ case ARM_INST_RFEIA:
+ case ARM_INST_RFEIB:
+ // TODO: ARM_INST_RFEDA, ARM_INST_RFEDB, ARM_INST_RFEIA, ARM_INST_RFEIB
+ break;
+
+ // Other instructions either can't change R15 or are "undefined" if you do,
+ // so no sane compiler should ever generate them & we don't care here.
+ // Also, R15 can only legally be used in a read-only manner for the
+ // various ARM addressing mode (to get PC-relative addressing of constants),
+ // but can NOT be used with any of the update modes.
+ default:
+ DNBLogError("%s should not be called for instruction code %d!", __FUNCTION__, decodedInstruction.instruction->code);
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+void
+DNBArchMachARM::EvaluateNextInstructionForSoftwareBreakpointSetup(nub_addr_t currentPC, uint32_t cpsr, bool currentPCIsThumb, nub_addr_t *nextPC, bool *nextPCIsThumb)
+{
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "DNBArchMachARM::EvaluateNextInstructionForSoftwareBreakpointSetup() called");
+
+ nub_addr_t targetPC = INVALID_NUB_ADDRESS;
+ uint32_t registerValue;
+ arm_error_t decodeError;
+ nub_addr_t currentPCInITBlock, nextPCInITBlock;
+ int i;
+ bool last_decoded_instruction_executes = true;
+
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: default nextPC=0x%8.8x (%s)", __FUNCTION__, *nextPC, *nextPCIsThumb ? "Thumb" : "ARM");
+
+ // Update *nextPC and *nextPCIsThumb for special cases
+ if (m_last_decode_thumb.itBlockRemaining) // we are in an IT block
+ {
+ // Set the nextPC to the PC of the instruction which will execute in the IT block
+ // If none of the instruction execute in the IT block based on the condition flags,
+ // then point to the instruction immediately following the IT block
+ const int itBlockRemaining = m_last_decode_thumb.itBlockRemaining;
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: itBlockRemaining=%8.8x", __FUNCTION__, itBlockRemaining);
+
+ // Determine the PC at which the next instruction resides
+ if (m_last_decode_arm.thumb16b)
+ currentPCInITBlock = currentPC + 2;
+ else
+ currentPCInITBlock = currentPC + 4;
+
+ for (i = 0; i < itBlockRemaining; i++)
+ {
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: currentPCInITBlock=%8.8x", __FUNCTION__, currentPCInITBlock);
+ decodeError = DecodeInstructionUsingDisassembler(currentPCInITBlock, cpsr, &m_last_decode_arm, &m_last_decode_thumb, &nextPCInITBlock);
+
+ if (decodeError != ARM_SUCCESS)
+ DNBLogError("unable to disassemble instruction at 0x%8.8lx", currentPCInITBlock);
+
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: condition=%d", __FUNCTION__, m_last_decode_arm.condition);
+ if (ConditionPassed(m_last_decode_arm.condition, cpsr))
+ {
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Condition codes matched for instruction %d", __FUNCTION__, i);
+ break; // break from the for loop
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Condition codes DID NOT matched for instruction %d", __FUNCTION__, i);
+ }
+
+ // update currentPC and nextPCInITBlock
+ currentPCInITBlock = nextPCInITBlock;
+ }
+
+ if (i == itBlockRemaining) // We came out of the IT block without executing any instructions
+ last_decoded_instruction_executes = false;
+
+ *nextPC = currentPCInITBlock;
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: After IT block step-through: *nextPC=%8.8x", __FUNCTION__, *nextPC);
+ }
+
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE,
+ "%s: cpsr = %8.8x, thumb16b = %d, thumb = %d, branch = %d, conditional = %d, knownTarget = %d, links = %d, canSwitchMode = %d, doesSwitchMode = %d",
+ __FUNCTION__,
+ cpsr,
+ m_last_decode_arm.thumb16b,
+ m_last_decode_arm.thumb,
+ m_last_decode_arm.branch,
+ m_last_decode_arm.conditional,
+ m_last_decode_arm.knownTarget,
+ m_last_decode_arm.links,
+ m_last_decode_arm.canSwitchMode,
+ m_last_decode_arm.doesSwitchMode);
+
+
+ if (last_decoded_instruction_executes && // Was this a conditional instruction that did execute?
+ m_last_decode_arm.branch && // Can this instruction change the PC?
+ (m_last_decode_arm.instruction->code != ARM_INST_SVC)) // If this instruction is not an SVC instruction
+ {
+ // Set targetPC. Compute if needed.
+ if (m_last_decode_arm.knownTarget)
+ {
+ // Fixed, known PC-relative
+ targetPC = m_last_decode_arm.targetPC;
+ }
+ else
+ {
+ // if targetPC is not known at compile time (PC-relative target), compute targetPC
+ if (!ComputeNextPC(currentPC, m_last_decode_arm, currentPCIsThumb, &targetPC))
+ {
+ DNBLogError("%s: Unable to compute targetPC for instruction at 0x%8.8lx", __FUNCTION__, currentPC);
+ targetPC = INVALID_NUB_ADDRESS;
+ }
+ }
+
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: targetPC=0x%8.8x, cpsr=0x%8.8x, condition=0x%hhx", __FUNCTION__, targetPC, cpsr, m_last_decode_arm.condition);
+
+ // Refine nextPC computation
+ if ((m_last_decode_arm.instruction->code == ARM_INST_CBZ) ||
+ (m_last_decode_arm.instruction->code == ARM_INST_CBNZ))
+ {
+ // Compare and branch on zero/non-zero (Thumb-16 only)
+ // Unusual condition check built into the instruction
+ registerValue = m_state.gpr.__r[m_last_decode_arm.op[REG_RD].value];
+
+ if (m_last_decode_arm.instruction->code == ARM_INST_CBZ)
+ {
+ if (registerValue == 0)
+ *nextPC = targetPC;
+ }
+ else
+ {
+ if (registerValue != 0)
+ *nextPC = targetPC;
+ }
+ }
+ else if (m_last_decode_arm.conditional) // Is the change conditional on flag results?
+ {
+ if (ConditionPassed(m_last_decode_arm.condition, cpsr)) // conditions match
+ {
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Condition matched!", __FUNCTION__);
+ *nextPC = targetPC;
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Condition did not match!", __FUNCTION__);
+ }
+ }
+ else
+ {
+ *nextPC = targetPC;
+ }
+
+ // Refine nextPCIsThumb computation
+ if (m_last_decode_arm.doesSwitchMode)
+ {
+ *nextPCIsThumb = !currentPCIsThumb;
+ }
+ else if (m_last_decode_arm.canSwitchMode)
+ {
+ // Legal to switch ARM <--> Thumb mode with this branch
+ // dependent on bit[0] of targetPC
+ *nextPCIsThumb = (*nextPC & 1u) != 0;
+ }
+ else
+ {
+ *nextPCIsThumb = currentPCIsThumb;
+ }
+ }
+
+ DNBLogThreadedIf(LOG_STEP, "%s: calculated nextPC=0x%8.8x (%s)", __FUNCTION__, *nextPC, *nextPCIsThumb ? "Thumb" : "ARM");
+}
+
+
+arm_error_t
+DNBArchMachARM::DecodeInstructionUsingDisassembler(nub_addr_t curr_pc, uint32_t curr_cpsr, arm_decoded_instruction_t *decodedInstruction, thumb_static_data_t *thumbStaticData, nub_addr_t *next_pc)
+{
+
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: pc=0x%8.8x, cpsr=0x%8.8x", __FUNCTION__, curr_pc, curr_cpsr);
+
+ const uint32_t isetstate_mask = MASK_CPSR_T | MASK_CPSR_J;
+ const uint32_t curr_isetstate = curr_cpsr & isetstate_mask;
+ uint32_t opcode32;
+ nub_addr_t nextPC = curr_pc;
+ arm_error_t decodeReturnCode = ARM_SUCCESS;
+
+ m_last_decode_pc = curr_pc;
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: last_decode_pc=0x%8.8x", __FUNCTION__, m_last_decode_pc);
+
+ switch (curr_isetstate) {
+ case 0x0: // ARM Instruction
+ // Read the ARM opcode
+ if (m_thread->Process()->Task().ReadMemory(curr_pc, 4, &opcode32) != 4)
+ {
+ DNBLogError("unable to read opcode bits 31:0 for an ARM opcode at 0x%8.8lx", curr_pc);
+ decodeReturnCode = ARM_ERROR;
+ }
+ else
+ {
+ nextPC += 4;
+ decodeReturnCode = ArmDisassembler((uint64_t)curr_pc, opcode32, false, decodedInstruction, NULL, 0, NULL, 0);
+
+ if (decodeReturnCode != ARM_SUCCESS)
+ DNBLogError("Unable to decode ARM instruction 0x%8.8x at 0x%8.8lx", opcode32, curr_pc);
+ }
+ break;
+
+ case 0x20: // Thumb Instruction
+ uint16_t opcode16;
+ // Read the a 16 bit Thumb opcode
+ if (m_thread->Process()->Task().ReadMemory(curr_pc, 2, &opcode16) != 2)
+ {
+ DNBLogError("unable to read opcode bits 15:0 for a thumb opcode at 0x%8.8lx", curr_pc);
+ decodeReturnCode = ARM_ERROR;
+ }
+ else
+ {
+ nextPC += 2;
+ opcode32 = opcode16;
+
+ decodeReturnCode = ThumbDisassembler((uint64_t)curr_pc, opcode16, false, false, thumbStaticData, decodedInstruction, NULL, 0, NULL, 0);
+
+ switch (decodeReturnCode) {
+ case ARM_SKIP:
+ // 32 bit thumb opcode
+ nextPC += 2;
+ if (m_thread->Process()->Task().ReadMemory(curr_pc+2, 2, &opcode16) != 2)
+ {
+ DNBLogError("unable to read opcode bits 15:0 for a thumb opcode at 0x%8.8lx", curr_pc+2);
+ }
+ else
+ {
+ opcode32 = (opcode32 << 16) | opcode16;
+
+ decodeReturnCode = ThumbDisassembler((uint64_t)(curr_pc+2), opcode16, false, false, thumbStaticData, decodedInstruction, NULL, 0, NULL, 0);
+
+ if (decodeReturnCode != ARM_SUCCESS)
+ DNBLogError("Unable to decode 2nd half of Thumb instruction 0x%8.4hx at 0x%8.8lx", opcode16, curr_pc+2);
+ break;
+ }
+ break;
+
+ case ARM_SUCCESS:
+ // 16 bit thumb opcode; at this point we are done decoding the opcode
+ break;
+
+ default:
+ DNBLogError("Unable to decode Thumb instruction 0x%8.4hx at 0x%8.8lx", opcode16, curr_pc);
+ decodeReturnCode = ARM_ERROR;
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (next_pc)
+ *next_pc = nextPC;
+
+ return decodeReturnCode;
+}
+
+nub_bool_t
+DNBArchMachARM::BreakpointHit(nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton)
+{
+ nub_addr_t bkpt_pc = (nub_addr_t)baton;
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s(pid = %i, tid = %4.4x, breakID = %u, baton = %p): Setting PC to 0x%8.8x", __FUNCTION__, pid, tid, breakID, baton, bkpt_pc);
+ return DNBThreadSetRegisterValueByID(pid, tid, REGISTER_SET_GENERIC, GENERIC_REGNUM_PC, bkpt_pc);
+}
+
+// Set the single step bit in the processor status register.
+kern_return_t
+DNBArchMachARM::SetSingleStepSoftwareBreakpoints()
+{
+ DNBError err;
+ err = GetGPRState(false);
+
+ if (err.Fail())
+ {
+ err.LogThreaded("%s: failed to read the GPR registers", __FUNCTION__);
+ return err.Error();
+ }
+
+ nub_addr_t curr_pc = m_state.gpr.__pc;
+ uint32_t curr_cpsr = m_state.gpr.__cpsr;
+ nub_addr_t next_pc = curr_pc;
+
+ bool curr_pc_is_thumb = (m_state.gpr.__cpsr & 0x20) != 0;
+ bool next_pc_is_thumb = curr_pc_is_thumb;
+
+ uint32_t curr_itstate = ((curr_cpsr & 0x6000000) >> 25) | ((curr_cpsr & 0xFC00) >> 8);
+ bool inITBlock = (curr_itstate & 0xF) ? 1 : 0;
+ bool lastInITBlock = ((curr_itstate & 0xF) == 0x8) ? 1 : 0;
+
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: curr_pc=0x%8.8x (%s), curr_itstate=0x%x, inITBlock=%d, lastInITBlock=%d", __FUNCTION__, curr_pc, curr_pc_is_thumb ? "Thumb" : "ARM", curr_itstate, inITBlock, lastInITBlock);
+
+ // If the instruction is not in the IT block, then decode using the Disassembler and compute next_pc
+ if (!inITBlock)
+ {
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Decoding an instruction NOT in the IT block", __FUNCTION__);
+
+ arm_error_t decodeReturnCode = DecodeInstructionUsingDisassembler(curr_pc, curr_cpsr, &m_last_decode_arm, &m_last_decode_thumb, &next_pc);
+
+ if (decodeReturnCode != ARM_SUCCESS)
+ {
+ err = KERN_INVALID_ARGUMENT;
+ DNBLogError("DNBArchMachARM::SetSingleStepSoftwareBreakpoints: Unable to disassemble instruction at 0x%8.8lx", curr_pc);
+ }
+ }
+ else
+ {
+ next_pc = curr_pc + ((m_last_decode_arm.thumb16b) ? 2 : 4);
+ }
+
+ // Instruction is NOT in the IT block OR
+ if (!inITBlock)
+ {
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: normal instruction", __FUNCTION__);
+ EvaluateNextInstructionForSoftwareBreakpointSetup(curr_pc, m_state.gpr.__cpsr, curr_pc_is_thumb, &next_pc, &next_pc_is_thumb);
+ }
+ else if (inITBlock && !m_last_decode_arm.setsFlags)
+ {
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: IT instruction that doesn't set flags", __FUNCTION__);
+ EvaluateNextInstructionForSoftwareBreakpointSetup(curr_pc, m_state.gpr.__cpsr, curr_pc_is_thumb, &next_pc, &next_pc_is_thumb);
+ }
+ else if (lastInITBlock && m_last_decode_arm.branch)
+ {
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: IT instruction which last in the IT block and is a branch", __FUNCTION__);
+ EvaluateNextInstructionForSoftwareBreakpointSetup(curr_pc, m_state.gpr.__cpsr, curr_pc_is_thumb, &next_pc, &next_pc_is_thumb);
+ }
+ else
+ {
+ // Instruction is in IT block and can modify the CPSR flags
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: IT instruction that sets flags", __FUNCTION__);
+
+ // NOTE: When this point of code is reached, the instruction at curr_pc has already been decoded
+ // inside the function ThreadDidStop(). Therefore m_last_decode_arm, m_last_decode_thumb
+ // reflect the decoded instruction at curr_pc
+
+ // If we find an instruction inside the IT block which will set/modify the condition flags (NZCV bits in CPSR),
+ // we set breakpoints at all remaining instructions inside the IT block starting from the instruction immediately
+ // following this one AND a breakpoint at the instruction immediately following the IT block. We do this because
+ // we cannot determine the next_pc until the instruction at which we are currently stopped executes. Hence we
+ // insert (m_last_decode_thumb.itBlockRemaining+1) 16-bit Thumb breakpoints at consecutive memory locations
+ // starting at addrOfNextInstructionInITBlock. We record these breakpoints in class variable m_sw_single_step_itblock_break_id[],
+ // and also record the total number of IT breakpoints set in the variable 'm_sw_single_step_itblock_break_count'.
+
+ // The instructions inside the IT block, which are replaced by the 16-bit Thumb breakpoints (opcode=0xDEFE)
+ // instructions, can be either Thumb-16 or Thumb-32. When a Thumb-32 instruction (say, inst#1) is replaced Thumb
+ // by a 16-bit breakpoint (OS only supports 16-bit breakpoints in Thumb mode and 32-bit breakpoints in ARM mode), the
+ // breakpoint for the next instruction (say instr#2) is saved in the upper half of this Thumb-32 (instr#1)
+ // instruction. Hence if the execution stops at Breakpoint2 corresponding to instr#2, the PC is offset by 16-bits.
+ // We therefore have to keep track of PC of each instruction in the IT block that is being replaced with the 16-bit
+ // Thumb breakpoint, to ensure that when the breakpoint is hit, the PC is adjusted to the correct value. We save
+ // the actual PC corresponding to each instruction in the IT block by associating a call back with each breakpoint
+ // we set and passing it as a baton. When the breakpoint hits and the callback routine is called, the routine
+ // adjusts the PC based on the baton that is passed to it.
+
+ nub_addr_t addrOfNextInstructionInITBlock, pcInITBlock, nextPCInITBlock, bpAddressInITBlock;
+ uint16_t opcode16;
+ uint32_t opcode32;
+
+ addrOfNextInstructionInITBlock = (m_last_decode_arm.thumb16b) ? curr_pc + 2 : curr_pc + 4;
+
+ pcInITBlock = addrOfNextInstructionInITBlock;
+
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: itBlockRemaining=%d", __FUNCTION__, m_last_decode_thumb.itBlockRemaining);
+
+ m_sw_single_step_itblock_break_count = 0;
+ for (int i = 0; i <= m_last_decode_thumb.itBlockRemaining; i++)
+ {
+ if (NUB_BREAK_ID_IS_VALID(m_sw_single_step_itblock_break_id[i]))
+ {
+ DNBLogError("FunctionProfiler::SetSingleStepSoftwareBreakpoints(): Array m_sw_single_step_itblock_break_id should not contain any valid breakpoint IDs at this point. But found a valid breakID=%d at index=%d", m_sw_single_step_itblock_break_id[i], i);
+ }
+ else
+ {
+ nextPCInITBlock = pcInITBlock;
+ // Compute nextPCInITBlock based on opcode present at pcInITBlock
+ if (m_thread->Process()->Task().ReadMemory(pcInITBlock, 2, &opcode16) == 2)
+ {
+ opcode32 = opcode16;
+ nextPCInITBlock += 2;
+
+ // Check for 32 bit thumb opcode and read the upper 16 bits if needed
+ if (((opcode32 & 0xE000) == 0xE000) && (opcode32 & 0x1800))
+ {
+ // Adjust 'next_pc_in_itblock' to point to the default next Thumb instruction for
+ // a 32 bit Thumb opcode
+ // Read bits 31:16 of a 32 bit Thumb opcode
+ if (m_thread->Process()->Task().ReadMemory(pcInITBlock+2, 2, &opcode16) == 2)
+ {
+ // 32 bit thumb opcode
+ opcode32 = (opcode32 << 16) | opcode16;
+ nextPCInITBlock += 2;
+ }
+ else
+ {
+ DNBLogError("FunctionProfiler::SetSingleStepSoftwareBreakpoints(): Unable to read opcode bits 31:16 for a 32 bit thumb opcode at pc=0x%8.8lx", nextPCInITBlock);
+ }
+ }
+ }
+ else
+ {
+ DNBLogError("FunctionProfiler::SetSingleStepSoftwareBreakpoints(): Error reading 16-bit Thumb instruction at pc=0x%8.8x", nextPCInITBlock);
+ }
+
+
+ // Set breakpoint and associate a callback function with it
+ bpAddressInITBlock = addrOfNextInstructionInITBlock + 2*i;
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Setting IT breakpoint[%d] at address: 0x%8.8x", __FUNCTION__, i, bpAddressInITBlock);
+
+ m_sw_single_step_itblock_break_id[i] = m_thread->Process()->CreateBreakpoint(bpAddressInITBlock, 2, false, m_thread->ThreadID());
+ if (!NUB_BREAK_ID_IS_VALID(m_sw_single_step_itblock_break_id[i]))
+ err = KERN_INVALID_ARGUMENT;
+ else
+ {
+ DNBLogThreadedIf(LOG_STEP, "%s: Set IT breakpoint[%i]=%d set at 0x%8.8x for instruction at 0x%8.8x", __FUNCTION__, i, m_sw_single_step_itblock_break_id[i], bpAddressInITBlock, pcInITBlock);
+
+ // Set the breakpoint callback for these special IT breakpoints
+ // so that if one of these breakpoints gets hit, it knows to
+ // update the PC to the original address of the conditional
+ // IT instruction.
+ DNBBreakpointSetCallback(m_thread->ProcessID(), m_sw_single_step_itblock_break_id[i], DNBArchMachARM::BreakpointHit, (void*)pcInITBlock);
+ m_sw_single_step_itblock_break_count++;
+ }
+ }
+
+ pcInITBlock = nextPCInITBlock;
+ }
+
+ DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Set %u IT software single breakpoints.", __FUNCTION__, m_sw_single_step_itblock_break_count);
+
+ }
+
+ DNBLogThreadedIf(LOG_STEP, "%s: next_pc=0x%8.8x (%s)", __FUNCTION__, next_pc, next_pc_is_thumb ? "Thumb" : "ARM");
+
+ if (next_pc & 0x1)
+ {
+ assert(next_pc_is_thumb);
+ }
+
+ if (next_pc_is_thumb)
+ {
+ next_pc &= ~0x1;
+ }
+ else
+ {
+ assert((next_pc & 0x3) == 0);
+ }
+
+ if (!inITBlock || (inITBlock && !m_last_decode_arm.setsFlags) || (lastInITBlock && m_last_decode_arm.branch))
+ {
+ err = KERN_SUCCESS;
+
+#if defined DNB_ARCH_MACH_ARM_DEBUG_SW_STEP
+ m_sw_single_step_next_pc = next_pc;
+ if (next_pc_is_thumb)
+ m_sw_single_step_next_pc |= 1; // Set bit zero if the next PC is expected to be Thumb
+#else
+ const DNBBreakpoint *bp = m_thread->Process()->Breakpoints().FindByAddress(next_pc);
+
+ if (bp == NULL)
+ {
+ m_sw_single_step_break_id = m_thread->Process()->CreateBreakpoint(next_pc, next_pc_is_thumb ? 2 : 4, false, m_thread->ThreadID());
+ if (!NUB_BREAK_ID_IS_VALID(m_sw_single_step_break_id))
+ err = KERN_INVALID_ARGUMENT;
+ DNBLogThreadedIf(LOG_STEP, "%s: software single step breakpoint with breakID=%d set at 0x%8.8x", __FUNCTION__, m_sw_single_step_break_id, next_pc);
+ }
+#endif
+ }
+
+ return err.Error();
+}
+
+uint32_t
+DNBArchMachARM::NumSupportedHardwareBreakpoints()
+{
+ // 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 = UINT_MAX;
+ if (g_num_supported_hw_breakpoints == UINT_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_breakpoints = 0;
+
+ // Read the DBGDIDR to get the number of available hardware breakpoints
+ // However, in some of our current armv7 processors, hardware
+ // breakpoints/watchpoints were not properly connected. So detect those
+ // cases using a field in a sysctl. For now we are using "hw.cpusubtype"
+ // field to distinguish CPU architectures. This is a hack until we can
+ // get <rdar://problem/6372672> fixed, at which point we will switch to
+ // using a different sysctl string that will tell us how many BRPs
+ // are available to us directly without having to read DBGDIDR.
+ uint32_t register_DBGDIDR;
+
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ uint32_t numBRPs = bits(register_DBGDIDR, 27, 24);
+ // Zero is reserved for the BRP count, so don't increment it if it is zero
+ if (numBRPs > 0)
+ numBRPs++;
+ DNBLogThreadedIf(LOG_THREAD, "DBGDIDR=0x%8.8x (number BRP pairs = %u)", register_DBGDIDR, numBRPs);
+
+ if (numBRPs > 0)
+ {
+ uint32_t cpusubtype;
+ size_t len;
+ len = sizeof(cpusubtype);
+ // TODO: remove this hack and change to using hw.optional.xx when implmented
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
+ {
+ DNBLogThreadedIf(LOG_THREAD, "hw.cpusubtype=0x%d", cpusubtype);
+ if (cpusubtype == CPU_SUBTYPE_ARM_V7)
+ DNBLogThreadedIf(LOG_THREAD, "Hardware breakpoints disabled for armv7 (rdar://problem/6372672)");
+ else
+ g_num_supported_hw_breakpoints = numBRPs;
+ }
+ }
+
+ }
+ return g_num_supported_hw_breakpoints;
+}
+
+
+uint32_t
+DNBArchMachARM::NumSupportedHardwareWatchpoints()
+{
+ // 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 = UINT_MAX;
+ if (g_num_supported_hw_watchpoints == UINT_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_watchpoints = 0;
+ // Read the DBGDIDR to get the number of available hardware breakpoints
+ // However, in some of our current armv7 processors, hardware
+ // breakpoints/watchpoints were not properly connected. So detect those
+ // cases using a field in a sysctl. For now we are using "hw.cpusubtype"
+ // field to distinguish CPU architectures. This is a hack until we can
+ // get <rdar://problem/6372672> fixed, at which point we will switch to
+ // using a different sysctl string that will tell us how many WRPs
+ // are available to us directly without having to read DBGDIDR.
+
+ uint32_t register_DBGDIDR;
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ uint32_t numWRPs = bits(register_DBGDIDR, 31, 28) + 1;
+ DNBLogThreadedIf(LOG_THREAD, "DBGDIDR=0x%8.8x (number WRP pairs = %u)", register_DBGDIDR, numWRPs);
+
+ if (numWRPs > 0)
+ {
+ uint32_t cpusubtype;
+ size_t len;
+ len = sizeof(cpusubtype);
+ // TODO: remove this hack and change to using hw.optional.xx when implmented
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
+ {
+ DNBLogThreadedIf(LOG_THREAD, "hw.cpusubtype=0x%d", cpusubtype);
+
+ if (cpusubtype == CPU_SUBTYPE_ARM_V7)
+ DNBLogThreadedIf(LOG_THREAD, "Hardware watchpoints disabled for armv7 (rdar://problem/6372672)");
+ else
+ g_num_supported_hw_watchpoints = numWRPs;
+ }
+ }
+
+ }
+ return g_num_supported_hw_watchpoints;
+}
+
+
+uint32_t
+DNBArchMachARM::EnableHardwareBreakpoint (nub_addr_t addr, nub_size_t size)
+{
+ // Make sure our address isn't bogus
+ if (addr & 1)
+ return INVALID_NUB_HW_INDEX;
+
+ kern_return_t kret = GetDBGState(false);
+
+ if (kret == KERN_SUCCESS)
+ {
+ const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints();
+ uint32_t i;
+ for (i=0; i<num_hw_breakpoints; ++i)
+ {
+ if ((m_state.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
+ m_state.dbg.__bvr[i] = addr & ~((nub_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
+ m_state.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
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchMachARM::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (Thumb)",
+ addr,
+ size,
+ i,
+ i,
+ m_state.dbg.__bvr[i],
+ m_state.dbg.__bcr[i]);
+ }
+ else if (size == 4)
+ {
+ // We have an ARM breakpoint
+ m_state.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
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchMachARM::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (ARM)",
+ addr,
+ size,
+ i,
+ i,
+ m_state.dbg.__bvr[i],
+ m_state.dbg.__bcr[i]);
+ }
+
+ kret = SetDBGState();
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchMachARM::EnableHardwareBreakpoint() SetDBGState() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchMachARM::EnableHardwareBreakpoint(addr = %8.8p, size = %u) => all hardware breakpoint resources are being used.", addr, size);
+ }
+ }
+
+ return INVALID_NUB_HW_INDEX;
+}
+
+bool
+DNBArchMachARM::DisableHardwareBreakpoint (uint32_t hw_index)
+{
+ kern_return_t kret = GetDBGState(false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareBreakpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ m_state.dbg.__bcr[hw_index] = 0;
+ DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchMachARM::SetHardwareBreakpoint( %u ) - BVR%u = 0x%8.8x BCR%u = 0x%8.8x",
+ hw_index,
+ hw_index,
+ m_state.dbg.__bvr[hw_index],
+ hw_index,
+ m_state.dbg.__bcr[hw_index]);
+
+ kret = SetDBGState();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t
+DNBArchMachARM::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write)
+{
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::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 INVALID_NUB_HW_INDEX;
+
+ // We must watch for either read or write
+ if (read == false && write == false)
+ return INVALID_NUB_HW_INDEX;
+
+ // Can't watch more than 4 bytes per WVR/WCR pair
+ if (size > 4)
+ return INVALID_NUB_HW_INDEX;
+
+ // 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;
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset);
+
+ uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset;
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask);
+ if (byte_mask > 0xfu)
+ return INVALID_NUB_HW_INDEX;
+
+ // Read the debug state
+ kern_return_t kret = GetDBGState(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 ((m_state.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
+ m_state.dbg.__wvr[i] = addr & ~((nub_addr_t)3);
+ m_state.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 = SetDBGState();
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint() SetDBGState() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints);
+ }
+ }
+ return INVALID_NUB_HW_INDEX;
+}
+
+bool
+DNBArchMachARM::DisableHardwareWatchpoint (uint32_t hw_index)
+{
+ kern_return_t kret = GetDBGState(false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ m_state.dbg.__wcr[hw_index] = 0;
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
+ hw_index,
+ hw_index,
+ m_state.dbg.__wvr[hw_index],
+ hw_index,
+ m_state.dbg.__wcr[hw_index]);
+
+ kret = SetDBGState();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Register information defintions for 32 bit ARMV6.
+//----------------------------------------------------------------------
+enum gpr_regnums
+{
+ e_regNumGPR_r0 = 0,
+ e_regNumGPR_r1,
+ e_regNumGPR_r2,
+ e_regNumGPR_r3,
+ e_regNumGPR_r4,
+ e_regNumGPR_r5,
+ e_regNumGPR_r6,
+ e_regNumGPR_r7,
+ e_regNumGPR_r8,
+ e_regNumGPR_r9,
+ e_regNumGPR_r10,
+ e_regNumGPR_r11,
+ e_regNumGPR_r12,
+ e_regNumGPR_sp,
+ e_regNumGPR_lr,
+ e_regNumGPR_pc,
+ e_regNumGPR_cpsr
+};
+
+// General purpose registers
+static DNBRegisterInfo g_gpr_registers[] =
+{
+ { "r0" , Uint, 4, Hex },
+ { "r1" , Uint, 4, Hex },
+ { "r2" , Uint, 4, Hex },
+ { "r3" , Uint, 4, Hex },
+ { "r4" , Uint, 4, Hex },
+ { "r5" , Uint, 4, Hex },
+ { "r6" , Uint, 4, Hex },
+ { "r7" , Uint, 4, Hex },
+ { "r8" , Uint, 4, Hex },
+ { "r9" , Uint, 4, Hex },
+ { "r10" , Uint, 4, Hex },
+ { "r11" , Uint, 4, Hex },
+ { "r12" , Uint, 4, Hex },
+ { "sp" , Uint, 4, Hex },
+ { "lr" , Uint, 4, Hex },
+ { "pc" , Uint, 4, Hex },
+ { "cpsr" , Uint, 4, Hex },
+};
+
+// Floating point registers
+static DNBRegisterInfo g_vfp_registers[] =
+{
+ { "s0" , IEEE754, 4, Float },
+ { "s1" , IEEE754, 4, Float },
+ { "s2" , IEEE754, 4, Float },
+ { "s3" , IEEE754, 4, Float },
+ { "s4" , IEEE754, 4, Float },
+ { "s5" , IEEE754, 4, Float },
+ { "s6" , IEEE754, 4, Float },
+ { "s7" , IEEE754, 4, Float },
+ { "s8" , IEEE754, 4, Float },
+ { "s9" , IEEE754, 4, Float },
+ { "s10" , IEEE754, 4, Float },
+ { "s11" , IEEE754, 4, Float },
+ { "s12" , IEEE754, 4, Float },
+ { "s13" , IEEE754, 4, Float },
+ { "s14" , IEEE754, 4, Float },
+ { "s15" , IEEE754, 4, Float },
+ { "s16" , IEEE754, 4, Float },
+ { "s17" , IEEE754, 4, Float },
+ { "s18" , IEEE754, 4, Float },
+ { "s19" , IEEE754, 4, Float },
+ { "s20" , IEEE754, 4, Float },
+ { "s21" , IEEE754, 4, Float },
+ { "s22" , IEEE754, 4, Float },
+ { "s23" , IEEE754, 4, Float },
+ { "s24" , IEEE754, 4, Float },
+ { "s25" , IEEE754, 4, Float },
+ { "s26" , IEEE754, 4, Float },
+ { "s27" , IEEE754, 4, Float },
+ { "s28" , IEEE754, 4, Float },
+ { "s29" , IEEE754, 4, Float },
+ { "s30" , IEEE754, 4, Float },
+ { "s31" , IEEE754, 4, Float },
+ { "fpscr" , Uint, 4, Hex }
+};
+
+// Exception registers
+
+static DNBRegisterInfo g_exc_registers[] =
+{
+ { "dar" , Uint, 4, Hex },
+ { "dsisr" , Uint, 4, Hex },
+ { "exception" , Uint, 4, Hex }
+};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = sizeof(g_gpr_registers)/sizeof(DNBRegisterInfo);
+const size_t k_num_vfp_registers = sizeof(g_vfp_registers)/sizeof(DNBRegisterInfo);
+const size_t k_num_exc_registers = sizeof(g_exc_registers)/sizeof(DNBRegisterInfo);
+// Total number of registers for this architecture
+const size_t k_num_armv6_registers = k_num_gpr_registers + k_num_vfp_registers + k_num_exc_registers;
+
+//----------------------------------------------------------------------
+// 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 DNBRegisterSetInfo g_reg_sets[] =
+{
+ { "ARMV6 Registers", NULL, k_num_armv6_registers },
+ { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers },
+ { "Floating Point Registers", g_vfp_registers, k_num_vfp_registers },
+ { "Exception State Registers", g_exc_registers, k_num_exc_registers }
+};
+// Total number of register sets for this architecture
+const size_t k_num_register_sets = sizeof(g_reg_sets)/sizeof(DNBRegisterSetInfo);
+
+
+const DNBRegisterSetInfo *
+DNBArchMachARM::GetRegisterSetInfo(nub_size_t *num_reg_sets) const
+{
+ *num_reg_sets = k_num_register_sets;
+ return g_reg_sets;
+}
+
+bool
+DNBArchMachARM::GetRegisterValue(int set, int reg, DNBRegisterValue *value)
+{
+ if (set == REGISTER_SET_GENERIC)
+ {
+ switch (reg)
+ {
+ case GENERIC_REGNUM_PC: // Program Counter
+ set = e_regSetGPR;
+ reg = e_regNumGPR_pc;
+ break;
+
+ case GENERIC_REGNUM_SP: // Stack Pointer
+ set = e_regSetGPR;
+ reg = e_regNumGPR_sp;
+ break;
+
+ case GENERIC_REGNUM_FP: // Frame Pointer
+ set = e_regSetGPR;
+ reg = e_regNumGPR_r7; // is this the right reg?
+ break;
+
+ case GENERIC_REGNUM_RA: // Return Address
+ set = e_regSetGPR;
+ reg = e_regNumGPR_lr;
+ break;
+
+ case GENERIC_REGNUM_FLAGS: // Processor flags register
+ set = e_regSetGPR;
+ reg = e_regNumGPR_cpsr;
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ if (GetRegisterState(set, false) != KERN_SUCCESS)
+ return false;
+
+ const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg);
+ if (regInfo)
+ {
+ value->info = *regInfo;
+ switch (set)
+ {
+ case e_regSetGPR:
+ if (reg < k_num_gpr_registers)
+ {
+ value->value.uint32 = m_state.gpr.__r[reg];
+ return true;
+ }
+ break;
+
+ case e_regSetVFP:
+ if (reg < 32)
+ {
+ value->value.uint32 = m_state.vfp.__r[reg];
+ return true;
+ }
+ else if (reg == 32)
+ {
+ value->value.uint32 = m_state.vfp.__fpscr;
+ return true;
+ }
+ break;
+
+ case e_regSetEXC:
+ if (reg < k_num_exc_registers)
+ {
+ value->value.uint32 = (&m_state.exc.__exception)[reg];
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+bool
+DNBArchMachARM::SetRegisterValue(int set, int reg, const DNBRegisterValue *value)
+{
+ if (set == REGISTER_SET_GENERIC)
+ {
+ switch (reg)
+ {
+ case GENERIC_REGNUM_PC: // Program Counter
+ set = e_regSetGPR;
+ reg = e_regNumGPR_pc;
+ break;
+
+ case GENERIC_REGNUM_SP: // Stack Pointer
+ set = e_regSetGPR;
+ reg = e_regNumGPR_sp;
+ break;
+
+ case GENERIC_REGNUM_FP: // Frame Pointer
+ set = e_regSetGPR;
+ reg = e_regNumGPR_r7;
+ break;
+
+ case GENERIC_REGNUM_RA: // Return Address
+ set = e_regSetGPR;
+ reg = e_regNumGPR_lr;
+ break;
+
+ case GENERIC_REGNUM_FLAGS: // Processor flags register
+ set = e_regSetGPR;
+ reg = e_regNumGPR_cpsr;
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ if (GetRegisterState(set, false) != KERN_SUCCESS)
+ return false;
+
+ bool success = false;
+ const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg);
+ if (regInfo)
+ {
+ switch (set)
+ {
+ case e_regSetGPR:
+ if (reg < k_num_gpr_registers)
+ {
+ m_state.gpr.__r[reg] = value->value.uint32;
+ success = true;
+ }
+ break;
+
+ case e_regSetVFP:
+ if (reg < 32)
+ {
+ m_state.vfp.__r[reg] = value->value.float64;
+ success = true;
+ }
+ else if (reg == 32)
+ {
+ m_state.vfp.__fpscr = value->value.uint32;
+ success = true;
+ }
+ break;
+
+ case e_regSetEXC:
+ if (reg < k_num_exc_registers)
+ {
+ (&m_state.exc.__exception)[reg] = value->value.uint32;
+ success = true;
+ }
+ break;
+ }
+
+ }
+ if (success)
+ return SetRegisterState(set) == KERN_SUCCESS;
+ return false;
+}
+
+kern_return_t
+DNBArchMachARM::GetRegisterState(int set, bool force)
+{
+ switch (set)
+ {
+ case e_regSetALL: return GetGPRState(force) |
+ GetVFPState(force) |
+ GetEXCState(force) |
+ GetDBGState(force);
+ case e_regSetGPR: return GetGPRState(force);
+ case e_regSetVFP: return GetVFPState(force);
+ case e_regSetEXC: return GetEXCState(force);
+ case e_regSetDBG: return GetDBGState(force);
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+kern_return_t
+DNBArchMachARM::SetRegisterState(int set)
+{
+ // Make sure we have a valid context to set.
+ kern_return_t err = GetRegisterState(set, false);
+ if (err != KERN_SUCCESS)
+ return err;
+
+ switch (set)
+ {
+ case e_regSetALL: return SetGPRState() |
+ SetVFPState() |
+ SetEXCState() |
+ SetDBGState();
+ case e_regSetGPR: return SetGPRState();
+ case e_regSetVFP: return SetVFPState();
+ case e_regSetEXC: return SetEXCState();
+ case e_regSetDBG: return SetDBGState();
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+bool
+DNBArchMachARM::RegisterSetStateIsValid (int set) const
+{
+ return m_state.RegsAreValid(set);
+}
+
+
+#endif // #if defined (__arm__)
+
diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h
new file mode 100644
index 00000000000..f40c891ce98
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h
@@ -0,0 +1,217 @@
+//===-- DNBArchImpl.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/25/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DebugNubArchMachARM_h__
+#define __DebugNubArchMachARM_h__
+
+#if defined (__arm__)
+
+#include "DNBArch.h"
+#include <ARMDisassembler/ARMDisassembler.h>
+
+class MachThread;
+
+class DNBArchMachARM : public DNBArchProtocol
+{
+public:
+ enum { kMaxNumThumbITBreakpoints = 4 };
+
+ DNBArchMachARM(MachThread *thread) :
+ m_thread(thread),
+ m_state(),
+ m_hw_single_chained_step_addr(INVALID_NUB_ADDRESS),
+ m_sw_single_step_next_pc(INVALID_NUB_ADDRESS),
+ m_sw_single_step_break_id(INVALID_NUB_BREAK_ID),
+ m_sw_single_step_itblock_break_count(0),
+ m_last_decode_pc(INVALID_NUB_ADDRESS)
+ {
+ memset(&m_dbg_save, 0, sizeof(m_dbg_save));
+ ThumbStaticsInit(&m_last_decode_thumb);
+ for (int i = 0; i < kMaxNumThumbITBreakpoints; i++)
+ m_sw_single_step_itblock_break_id[i] = INVALID_NUB_BREAK_ID;
+ }
+
+ virtual ~DNBArchMachARM()
+ {
+ }
+
+ virtual const DNBRegisterSetInfo *
+ GetRegisterSetInfo(nub_size_t *num_reg_sets) const;
+ virtual bool GetRegisterValue(int set, int reg, DNBRegisterValue *value);
+ virtual bool SetRegisterValue(int set, int reg, const DNBRegisterValue *value);
+
+ virtual kern_return_t GetRegisterState (int set, bool force);
+ virtual kern_return_t SetRegisterState (int set);
+ virtual bool RegisterSetStateIsValid (int set) const;
+
+ virtual uint64_t GetPC(uint64_t failValue); // Get program counter
+ virtual kern_return_t SetPC(uint64_t value);
+ virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer
+ virtual void ThreadWillResume();
+ virtual bool ThreadDidStop();
+
+ static const uint8_t * const SoftwareBreakpointOpcode (nub_size_t byte_size);
+ static uint32_t GetCPUType();
+
+ virtual uint32_t NumSupportedHardwareBreakpoints();
+ virtual uint32_t NumSupportedHardwareWatchpoints();
+ virtual uint32_t EnableHardwareBreakpoint (nub_addr_t addr, nub_size_t size);
+ virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write);
+ virtual bool DisableHardwareBreakpoint (uint32_t hw_break_index);
+ virtual bool DisableHardwareWatchpoint (uint32_t hw_break_index);
+ virtual bool StepNotComplete ();
+
+protected:
+
+
+ kern_return_t EnableHardwareSingleStep (bool enable);
+ kern_return_t SetSingleStepSoftwareBreakpoints ();
+
+ bool ConditionPassed(uint8_t condition, uint32_t cpsr);
+ bool ComputeNextPC(nub_addr_t currentPC, arm_decoded_instruction_t decodedInstruction, bool currentPCIsThumb, nub_addr_t *targetPC);
+ void EvaluateNextInstructionForSoftwareBreakpointSetup(nub_addr_t currentPC, uint32_t cpsr, bool currentPCIsThumb, nub_addr_t *nextPC, bool *nextPCIsThumb);
+ void DecodeITBlockInstructions(nub_addr_t curr_pc);
+ arm_error_t DecodeInstructionUsingDisassembler(nub_addr_t curr_pc, uint32_t curr_cpsr, arm_decoded_instruction_t *decodedInstruction, thumb_static_data_t *thumbStaticData, nub_addr_t *next_pc);
+ static nub_bool_t BreakpointHit (nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton);
+
+ typedef enum RegisterSetTag
+ {
+ e_regSetALL = REGISTER_SET_ALL,
+ e_regSetGPR = ARM_THREAD_STATE,
+ e_regSetVFP = ARM_VFP_STATE,
+ e_regSetEXC = ARM_EXCEPTION_STATE,
+ e_regSetDBG = ARM_DEBUG_STATE,
+ kNumRegisterSets
+ } RegisterSet;
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ struct State
+ {
+ arm_thread_state_t gpr;
+ arm_vfp_state_t vfp;
+ arm_exception_state_t exc;
+ arm_debug_state_t dbg;
+ kern_return_t gpr_errs[2]; // Read/Write errors
+ kern_return_t vfp_errs[2]; // Read/Write errors
+ kern_return_t exc_errs[2]; // Read/Write errors
+ kern_return_t dbg_errs[2]; // Read/Write errors
+ State()
+ {
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ vfp_errs[i] = -1;
+ exc_errs[i] = -1;
+ dbg_errs[i] = -1;
+ }
+ }
+ void InvalidateRegisterSetState(int set)
+ {
+ SetError (set, Read, -1);
+ }
+ kern_return_t GetError (int set, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (set)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case e_regSetALL: return gpr_errs[err_idx] |
+ vfp_errs[err_idx] |
+ exc_errs[err_idx] |
+ dbg_errs[err_idx] ;
+ case e_regSetGPR: return gpr_errs[err_idx];
+ case e_regSetVFP: return vfp_errs[err_idx];
+ case e_regSetEXC: return exc_errs[err_idx];
+ case e_regSetDBG: return dbg_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+ bool SetError (int set, uint32_t err_idx, kern_return_t err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (set)
+ {
+ case e_regSetALL:
+ gpr_errs[err_idx] = err;
+ vfp_errs[err_idx] = err;
+ dbg_errs[err_idx] = err;
+ exc_errs[err_idx] = err;
+ return true;
+
+ case e_regSetGPR:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case e_regSetVFP:
+ vfp_errs[err_idx] = err;
+ return true;
+
+ case e_regSetEXC:
+ exc_errs[err_idx] = err;
+ return true;
+
+ case e_regSetDBG:
+ dbg_errs[err_idx] = err;
+ return true;
+ default: break;
+ }
+ }
+ return false;
+ }
+ bool RegsAreValid (int set) const
+ {
+ return GetError(set, Read) == KERN_SUCCESS;
+ }
+ };
+
+ kern_return_t GetGPRState (bool force);
+ kern_return_t GetVFPState (bool force);
+ kern_return_t GetEXCState (bool force);
+ kern_return_t GetDBGState (bool force);
+
+ kern_return_t SetGPRState ();
+ kern_return_t SetVFPState ();
+ kern_return_t SetEXCState ();
+ kern_return_t SetDBGState ();
+protected:
+ MachThread * m_thread;
+ State m_state;
+ arm_debug_state_t m_dbg_save;
+ nub_addr_t m_hw_single_chained_step_addr;
+ // Software single stepping support
+ nub_addr_t m_sw_single_step_next_pc;
+ nub_break_t m_sw_single_step_break_id;
+ nub_break_t m_sw_single_step_itblock_break_id[kMaxNumThumbITBreakpoints];
+ nub_addr_t m_sw_single_step_itblock_break_count;
+ // Disassembler state
+ thumb_static_data_t m_last_decode_thumb;
+ arm_decoded_instruction_t m_last_decode_arm;
+ nub_addr_t m_last_decode_pc;
+
+};
+
+typedef DNBArchMachARM DNBArch;
+#endif // #if defined (__arm__)
+#endif // #ifndef __DebugNubArchMachARM_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/dbgnub-mig.defs b/lldb/tools/debugserver/source/MacOSX/dbgnub-mig.defs
new file mode 100644
index 00000000000..9b1554f8708
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/dbgnub-mig.defs
@@ -0,0 +1,16 @@
+/*
+ * nub.defs
+ */
+
+/*
+ * DNBConfig.h is autogenerated by a perl script that is run as a build
+ * script in XCode. XCode is responsible for calling the script and setting
+ * the include paths correctly to locate it. The file will exist in the
+ * derived sources directory in the build folder.
+ *
+ */
+
+#include "DNBConfig.h"
+
+
+#import <mach/mach_exc.defs>
diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
new file mode 100644
index 00000000000..0a0601f6378
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
@@ -0,0 +1,879 @@
+//===-- DNBArchImplI386.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/25/07.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined (__i386__)
+
+#include <sys/cdefs.h>
+
+#include "MacOSX/i386/DNBArchImplI386.h"
+#include "DNBLog.h"
+#include "MachThread.h"
+#include "MachProcess.h"
+
+static const uint8_t g_breakpoint_opcode[] = { 0xCC };
+
+enum
+{
+ gpr_eax = 0,
+ gpr_ebx = 1,
+ gpr_ecx = 2,
+ gpr_edx = 3,
+ gpr_edi = 4,
+ gpr_esi = 5,
+ gpr_ebp = 6,
+ gpr_esp = 7,
+ gpr_ss = 8,
+ gpr_eflags = 9,
+ gpr_eip = 10,
+ gpr_cs = 11,
+ gpr_ds = 12,
+ gpr_es = 13,
+ gpr_fs = 14,
+ gpr_gs = 15,
+ k_num_gpr_regs
+};
+
+enum {
+ 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,
+ k_num_fpu_regs,
+
+ // 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 {
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+ k_num_exc_regs,
+};
+
+
+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
+};
+
+
+const uint8_t * const
+DNBArchImplI386::SoftwareBreakpointOpcode (nub_size_t byte_size)
+{
+ if (byte_size == 1)
+ return g_breakpoint_opcode;
+ return NULL;
+}
+
+uint32_t
+DNBArchImplI386::GetCPUType()
+{
+ return CPU_TYPE_I386;
+}
+
+uint64_t
+DNBArchImplI386::GetPC(uint64_t failValue)
+{
+ // Get program counter
+ if (GetGPRState(false) == KERN_SUCCESS)
+ return m_state.context.gpr.__eip;
+ return failValue;
+}
+
+kern_return_t
+DNBArchImplI386::SetPC(uint64_t value)
+{
+ // Get program counter
+ kern_return_t err = GetGPRState(false);
+ if (err == KERN_SUCCESS)
+ {
+ m_state.context.gpr.__eip = value;
+ err = SetGPRState();
+ }
+ return err == KERN_SUCCESS;
+}
+
+uint64_t
+DNBArchImplI386::GetSP(uint64_t failValue)
+{
+ // Get stack pointer
+ if (GetGPRState(false) == KERN_SUCCESS)
+ return m_state.context.gpr.__esp;
+ return failValue;
+}
+
+// Uncomment the value below to verify the values in the debugger.
+//#define DEBUG_GPR_VALUES 1 // DO NOT CHECK IN WITH THIS DEFINE ENABLED
+//#define SET_GPR(reg) m_state.context.gpr.__##reg = gpr_##reg
+
+kern_return_t
+DNBArchImplI386::GetGPRState(bool force)
+{
+ if (force || m_state.GetError(e_regSetGPR, Read))
+ {
+#if DEBUG_GPR_VALUES
+ SET_GPR(eax);
+ SET_GPR(ebx);
+ SET_GPR(ecx);
+ SET_GPR(edx);
+ SET_GPR(edi);
+ SET_GPR(esi);
+ SET_GPR(ebp);
+ SET_GPR(esp);
+ SET_GPR(ss);
+ SET_GPR(eflags);
+ SET_GPR(eip);
+ SET_GPR(cs);
+ SET_GPR(ds);
+ SET_GPR(es);
+ SET_GPR(fs);
+ SET_GPR(gs);
+ m_state.SetError(e_regSetGPR, Read, 0);
+#else
+ mach_msg_type_number_t count = e_regSetWordSizeGPR;
+ m_state.SetError(e_regSetGPR, Read, ::thread_get_state(m_thread->ThreadID(), x86_THREAD_STATE32, (thread_state_t)&m_state.context.gpr, &count));
+#endif
+ }
+ return m_state.GetError(e_regSetGPR, Read);
+}
+
+// Uncomment the value below to verify the values in the debugger.
+//#define DEBUG_FPU_VALUES 1 // DO NOT CHECK IN WITH THIS DEFINE ENABLED
+
+kern_return_t
+DNBArchImplI386::GetFPUState(bool force)
+{
+ if (force || m_state.GetError(e_regSetFPU, Read))
+ {
+#if DEBUG_FPU_VALUES
+ m_state.context.fpu.__fpu_reserved[0] = -1;
+ m_state.context.fpu.__fpu_reserved[1] = -1;
+ *(uint16_t *)&(m_state.context.fpu.__fpu_fcw) = 0x1234;
+ *(uint16_t *)&(m_state.context.fpu.__fpu_fsw) = 0x5678;
+ m_state.context.fpu.__fpu_ftw = 1;
+ m_state.context.fpu.__fpu_rsrv1 = UINT8_MAX;
+ m_state.context.fpu.__fpu_fop = 2;
+ m_state.context.fpu.__fpu_ip = 3;
+ m_state.context.fpu.__fpu_cs = 4;
+ m_state.context.fpu.__fpu_rsrv2 = 5;
+ m_state.context.fpu.__fpu_dp = 6;
+ m_state.context.fpu.__fpu_ds = 7;
+ m_state.context.fpu.__fpu_rsrv3 = UINT16_MAX;
+ m_state.context.fpu.__fpu_mxcsr = 8;
+ m_state.context.fpu.__fpu_mxcsrmask = 9;
+ int i;
+ for (i=0; i<16; ++i)
+ {
+ if (i<10)
+ {
+ m_state.context.fpu.__fpu_stmm0.__mmst_reg[i] = 'a';
+ m_state.context.fpu.__fpu_stmm1.__mmst_reg[i] = 'b';
+ m_state.context.fpu.__fpu_stmm2.__mmst_reg[i] = 'c';
+ m_state.context.fpu.__fpu_stmm3.__mmst_reg[i] = 'd';
+ m_state.context.fpu.__fpu_stmm4.__mmst_reg[i] = 'e';
+ m_state.context.fpu.__fpu_stmm5.__mmst_reg[i] = 'f';
+ m_state.context.fpu.__fpu_stmm6.__mmst_reg[i] = 'g';
+ m_state.context.fpu.__fpu_stmm7.__mmst_reg[i] = 'h';
+ }
+ else
+ {
+ m_state.context.fpu.__fpu_stmm0.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm1.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm2.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm3.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm4.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm5.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm6.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm7.__mmst_reg[i] = INT8_MIN;
+ }
+
+ m_state.context.fpu.__fpu_xmm0.__xmm_reg[i] = '0';
+ m_state.context.fpu.__fpu_xmm1.__xmm_reg[i] = '1';
+ m_state.context.fpu.__fpu_xmm2.__xmm_reg[i] = '2';
+ m_state.context.fpu.__fpu_xmm3.__xmm_reg[i] = '3';
+ m_state.context.fpu.__fpu_xmm4.__xmm_reg[i] = '4';
+ m_state.context.fpu.__fpu_xmm5.__xmm_reg[i] = '5';
+ m_state.context.fpu.__fpu_xmm6.__xmm_reg[i] = '6';
+ m_state.context.fpu.__fpu_xmm7.__xmm_reg[i] = '7';
+ }
+ for (i=0; i<sizeof(m_state.context.fpu.__fpu_rsrv4); ++i)
+ m_state.context.fpu.__fpu_rsrv4[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_reserved1 = -1;
+ m_state.SetError(e_regSetFPU, Read, 0);
+#else
+ mach_msg_type_number_t count = e_regSetWordSizeFPR;
+ m_state.SetError(e_regSetFPU, Read, ::thread_get_state(m_thread->ThreadID(), x86_FLOAT_STATE32, (thread_state_t)&m_state.context.fpu, &count));
+#endif
+ }
+ return m_state.GetError(e_regSetFPU, Read);
+}
+
+kern_return_t
+DNBArchImplI386::GetEXCState(bool force)
+{
+ if (force || m_state.GetError(e_regSetEXC, Read))
+ {
+ mach_msg_type_number_t count = e_regSetWordSizeEXC;
+ m_state.SetError(e_regSetEXC, Read, ::thread_get_state(m_thread->ThreadID(), x86_EXCEPTION_STATE32, (thread_state_t)&m_state.context.exc, &count));
+ }
+ return m_state.GetError(e_regSetEXC, Read);
+}
+
+kern_return_t
+DNBArchImplI386::SetGPRState()
+{
+ m_state.SetError(e_regSetGPR, Write, ::thread_set_state(m_thread->ThreadID(), x86_THREAD_STATE32, (thread_state_t)&m_state.context.gpr, e_regSetWordSizeGPR));
+ return m_state.GetError(e_regSetGPR, Write);
+}
+
+kern_return_t
+DNBArchImplI386::SetFPUState()
+{
+ m_state.SetError(e_regSetFPU, Write, ::thread_set_state(m_thread->ThreadID(), x86_FLOAT_STATE32, (thread_state_t)&m_state.context.fpu, e_regSetWordSizeFPR));
+ return m_state.GetError(e_regSetFPU, Write);
+}
+
+kern_return_t
+DNBArchImplI386::SetEXCState()
+{
+ m_state.SetError(e_regSetEXC, Write, ::thread_set_state(m_thread->ThreadID(), x86_EXCEPTION_STATE32, (thread_state_t)&m_state.context.exc, e_regSetWordSizeEXC));
+ return m_state.GetError(e_regSetEXC, Write);
+}
+
+void
+DNBArchImplI386::ThreadWillResume()
+{
+ // Do we need to step this thread? If so, let the mach thread tell us so.
+ if (m_thread->IsStepping())
+ {
+ // This is the primary thread, let the arch do anything it needs
+ EnableHardwareSingleStep(true) == KERN_SUCCESS;
+ }
+}
+
+bool
+DNBArchImplI386::ThreadDidStop()
+{
+ bool success = true;
+
+ m_state.InvalidateAllRegisterStates();
+
+ // Are we stepping a single instruction?
+ if (GetGPRState(true) == KERN_SUCCESS)
+ {
+ // We are single stepping, was this the primary thread?
+ if (m_thread->IsStepping())
+ {
+ // This was the primary thread, we need to clear the trace
+ // bit if so.
+ success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
+ }
+ else
+ {
+ // The MachThread will automatically restore the suspend count
+ // in ThreadDidStop(), so we don't need to do anything here if
+ // we weren't the primary thread the last time
+ }
+ }
+ return success;
+}
+
+bool
+DNBArchImplI386::NotifyException(MachException::Data& exc)
+{
+ switch (exc.exc_type)
+ {
+ case EXC_BAD_ACCESS:
+ break;
+ case EXC_BAD_INSTRUCTION:
+ break;
+ case EXC_ARITHMETIC:
+ break;
+ case EXC_EMULATION:
+ break;
+ case EXC_SOFTWARE:
+ break;
+ case EXC_BREAKPOINT:
+ if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2)
+ {
+ nub_addr_t pc = GetPC(INVALID_NUB_ADDRESS);
+ if (pc != INVALID_NUB_ADDRESS && pc > 0)
+ {
+ pc -= 1;
+ // Check for a breakpoint at one byte prior to the current PC value
+ // since the PC will be just past the trap.
+
+ nub_break_t breakID = m_thread->Process()->Breakpoints().FindIDByAddress(pc);
+ if (NUB_BREAK_ID_IS_VALID(breakID))
+ {
+ // Backup the PC for i386 since the trap was taken and the PC
+ // is at the address following the single byte trap instruction.
+ if (m_state.context.gpr.__eip > 0)
+ {
+ m_state.context.gpr.__eip = pc;
+ // Write the new PC back out
+ SetGPRState ();
+ }
+
+ m_thread->SetCurrentBreakpoint(breakID);
+ }
+ return true;
+ }
+ }
+ break;
+ case EXC_SYSCALL:
+ break;
+ case EXC_MACH_SYSCALL:
+ break;
+ case EXC_RPC_ALERT:
+ break;
+ }
+ return false;
+}
+
+
+// Set the single step bit in the processor status register.
+kern_return_t
+DNBArchImplI386::EnableHardwareSingleStep (bool enable)
+{
+ if (GetGPRState(false) == KERN_SUCCESS)
+ {
+ const uint32_t trace_bit = 0x100u;
+ if (enable)
+ m_state.context.gpr.__eflags |= trace_bit;
+ else
+ m_state.context.gpr.__eflags &= ~trace_bit;
+ return SetGPRState();
+ }
+ return m_state.GetError(e_regSetGPR, Read);
+}
+
+
+//----------------------------------------------------------------------
+// Register information defintions
+//----------------------------------------------------------------------
+
+
+#define GPR_OFFSET(reg) (offsetof (DNBArchImplI386::GPR, __##reg))
+#define FPU_OFFSET(reg) (offsetof (DNBArchImplI386::FPU, __fpu_##reg) + offsetof (DNBArchImplI386::Context, fpu))
+#define EXC_OFFSET(reg) (offsetof (DNBArchImplI386::EXC, __##reg) + offsetof (DNBArchImplI386::Context, exc))
+
+#define GPR_SIZE(reg) (sizeof(((DNBArchImplI386::GPR *)NULL)->__##reg))
+#define FPU_SIZE_UINT(reg) (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg))
+#define FPU_SIZE_MMST(reg) (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg.__mmst_reg))
+#define FPU_SIZE_XMM(reg) (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg.__xmm_reg))
+#define EXC_SIZE(reg) (sizeof(((DNBArchImplI386::EXC *)NULL)->__##reg))
+
+// 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.
+
+// General purpose registers for 64 bit
+const DNBRegisterInfo
+DNBArchImplI386::g_gpr_registers[] =
+{
+{ e_regSetGPR, gpr_eax, "eax" , NULL , Uint, Hex, GPR_SIZE(eax), GPR_OFFSET(eax) , gcc_eax , dwarf_eax , -1 , gdb_eax },
+{ e_regSetGPR, gpr_ebx, "ebx" , NULL , Uint, Hex, GPR_SIZE(ebx), GPR_OFFSET(ebx) , gcc_ebx , dwarf_ebx , -1 , gdb_ebx },
+{ e_regSetGPR, gpr_ecx, "ecx" , NULL , Uint, Hex, GPR_SIZE(ecx), GPR_OFFSET(ecx) , gcc_ecx , dwarf_ecx , -1 , gdb_ecx },
+{ e_regSetGPR, gpr_edx, "edx" , NULL , Uint, Hex, GPR_SIZE(edx), GPR_OFFSET(edx) , gcc_edx , dwarf_edx , -1 , gdb_edx },
+{ e_regSetGPR, gpr_edi, "edi" , NULL , Uint, Hex, GPR_SIZE(edi), GPR_OFFSET(edi) , gcc_edi , dwarf_edi , -1 , gdb_edi },
+{ e_regSetGPR, gpr_esi, "esi" , NULL , Uint, Hex, GPR_SIZE(esi), GPR_OFFSET(esi) , gcc_esi , dwarf_esi , -1 , gdb_esi },
+{ e_regSetGPR, gpr_ebp, "ebp" , "fp" , Uint, Hex, GPR_SIZE(ebp), GPR_OFFSET(ebp) , gcc_ebp , dwarf_ebp , GENERIC_REGNUM_FP , gdb_ebp },
+{ e_regSetGPR, gpr_esp, "esp" , "sp" , Uint, Hex, GPR_SIZE(esp), GPR_OFFSET(esp) , gcc_esp , dwarf_esp , GENERIC_REGNUM_SP , gdb_esp },
+{ e_regSetGPR, gpr_ss, "ss" , NULL , Uint, Hex, GPR_SIZE(ss), GPR_OFFSET(ss) , -1 , -1 , -1 , gdb_ss },
+{ e_regSetGPR, gpr_eflags, "eflags", "flags" , Uint, Hex, GPR_SIZE(eflags), GPR_OFFSET(eflags) , gcc_eflags, dwarf_eflags , GENERIC_REGNUM_FLAGS , gdb_eflags},
+{ e_regSetGPR, gpr_eip, "eip" , "pc" , Uint, Hex, GPR_SIZE(eip), GPR_OFFSET(eip) , gcc_eip , dwarf_eip , GENERIC_REGNUM_PC , gdb_eip },
+{ e_regSetGPR, gpr_cs, "cs" , NULL , Uint, Hex, GPR_SIZE(cs), GPR_OFFSET(cs) , -1 , -1 , -1 , gdb_cs },
+{ e_regSetGPR, gpr_ds, "ds" , NULL , Uint, Hex, GPR_SIZE(ds), GPR_OFFSET(ds) , -1 , -1 , -1 , gdb_ds },
+{ e_regSetGPR, gpr_es, "es" , NULL , Uint, Hex, GPR_SIZE(es), GPR_OFFSET(es) , -1 , -1 , -1 , gdb_es },
+{ e_regSetGPR, gpr_fs, "fs" , NULL , Uint, Hex, GPR_SIZE(fs), GPR_OFFSET(fs) , -1 , -1 , -1 , gdb_fs },
+{ e_regSetGPR, gpr_gs, "gs" , NULL , Uint, Hex, GPR_SIZE(gs), GPR_OFFSET(gs) , -1 , -1 , -1 , gdb_gs }
+};
+
+
+const DNBRegisterInfo
+DNBArchImplI386::g_fpu_registers[] =
+{
+{ e_regSetFPU, fpu_fcw , "fctrl" , NULL, Uint, Hex, FPU_SIZE_UINT(fcw) , FPU_OFFSET(fcw) , -1, -1, -1, -1 },
+{ e_regSetFPU, fpu_fsw , "fstat" , NULL, Uint, Hex, FPU_SIZE_UINT(fsw) , FPU_OFFSET(fsw) , -1, -1, -1, -1 },
+{ e_regSetFPU, fpu_ftw , "ftag" , NULL, Uint, Hex, FPU_SIZE_UINT(ftw) , FPU_OFFSET(ftw) , -1, -1, -1, -1 },
+{ e_regSetFPU, fpu_fop , "fop" , NULL, Uint, Hex, FPU_SIZE_UINT(fop) , FPU_OFFSET(fop) , -1, -1, -1, -1 },
+{ e_regSetFPU, fpu_ip , "fioff" , NULL, Uint, Hex, FPU_SIZE_UINT(ip) , FPU_OFFSET(ip) , -1, -1, -1, -1 },
+{ e_regSetFPU, fpu_cs , "fiseg" , NULL, Uint, Hex, FPU_SIZE_UINT(cs) , FPU_OFFSET(cs) , -1, -1, -1, -1 },
+{ e_regSetFPU, fpu_dp , "fooff" , NULL, Uint, Hex, FPU_SIZE_UINT(dp) , FPU_OFFSET(dp) , -1, -1, -1, -1 },
+{ e_regSetFPU, fpu_ds , "foseg" , NULL, Uint, Hex, FPU_SIZE_UINT(ds) , FPU_OFFSET(ds) , -1, -1, -1, -1 },
+{ e_regSetFPU, fpu_mxcsr , "mxcsr" , NULL, Uint, Hex, FPU_SIZE_UINT(mxcsr) , FPU_OFFSET(mxcsr) , -1, -1, -1, -1 },
+{ e_regSetFPU, fpu_mxcsrmask, "mxcsrmask" , NULL, Uint, Hex, FPU_SIZE_UINT(mxcsrmask) , FPU_OFFSET(mxcsrmask) , -1, -1, -1, -1 },
+
+{ e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm0), FPU_OFFSET(stmm0), -1, dwarf_stmm0, -1, gdb_stmm0 },
+{ e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm1), FPU_OFFSET(stmm1), -1, dwarf_stmm1, -1, gdb_stmm1 },
+{ e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm2), FPU_OFFSET(stmm2), -1, dwarf_stmm2, -1, gdb_stmm2 },
+{ e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm3), FPU_OFFSET(stmm3), -1, dwarf_stmm3, -1, gdb_stmm3 },
+{ e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm4), FPU_OFFSET(stmm4), -1, dwarf_stmm4, -1, gdb_stmm4 },
+{ e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm5), FPU_OFFSET(stmm5), -1, dwarf_stmm5, -1, gdb_stmm5 },
+{ e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm6), FPU_OFFSET(stmm6), -1, dwarf_stmm6, -1, gdb_stmm6 },
+{ e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm7), FPU_OFFSET(stmm7), -1, dwarf_stmm7, -1, gdb_stmm7 },
+
+{ e_regSetFPU, fpu_xmm0, "xmm0", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm0), FPU_OFFSET(xmm0), -1, dwarf_xmm0, -1, gdb_xmm0 },
+{ e_regSetFPU, fpu_xmm1, "xmm1", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm1), FPU_OFFSET(xmm1), -1, dwarf_xmm1, -1, gdb_xmm1 },
+{ e_regSetFPU, fpu_xmm2, "xmm2", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm2), FPU_OFFSET(xmm2), -1, dwarf_xmm2, -1, gdb_xmm2 },
+{ e_regSetFPU, fpu_xmm3, "xmm3", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm3), FPU_OFFSET(xmm3), -1, dwarf_xmm3, -1, gdb_xmm3 },
+{ e_regSetFPU, fpu_xmm4, "xmm4", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm4), FPU_OFFSET(xmm4), -1, dwarf_xmm4, -1, gdb_xmm4 },
+{ e_regSetFPU, fpu_xmm5, "xmm5", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm5), FPU_OFFSET(xmm5), -1, dwarf_xmm5, -1, gdb_xmm5 },
+{ e_regSetFPU, fpu_xmm6, "xmm6", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm6), FPU_OFFSET(xmm6), -1, dwarf_xmm6, -1, gdb_xmm6 },
+{ e_regSetFPU, fpu_xmm7, "xmm7", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm7), FPU_OFFSET(xmm7), -1, dwarf_xmm7, -1, gdb_xmm7 }
+};
+
+
+
+const DNBRegisterInfo
+DNBArchImplI386::g_exc_registers[] =
+{
+{ e_regSetEXC, exc_trapno, "trapno" , NULL, Uint, Hex, EXC_SIZE (trapno) , EXC_OFFSET (trapno) , -1, -1, -1, -1 },
+{ e_regSetEXC, exc_err, "err" , NULL, Uint, Hex, EXC_SIZE (err) , EXC_OFFSET (err) , -1, -1, -1, -1 },
+{ e_regSetEXC, exc_faultvaddr, "faultvaddr", NULL, Uint, Hex, EXC_SIZE (faultvaddr), EXC_OFFSET (faultvaddr) , -1, -1, -1, -1 }
+};
+
+// Number of registers in each register set
+const size_t DNBArchImplI386::k_num_gpr_registers = sizeof(g_gpr_registers)/sizeof(DNBRegisterInfo);
+const size_t DNBArchImplI386::k_num_fpu_registers = sizeof(g_fpu_registers)/sizeof(DNBRegisterInfo);
+const size_t DNBArchImplI386::k_num_exc_registers = sizeof(g_exc_registers)/sizeof(DNBRegisterInfo);
+const size_t DNBArchImplI386::k_num_all_registers = k_num_gpr_registers + k_num_fpu_registers + k_num_exc_registers;
+
+//----------------------------------------------------------------------
+// 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.
+//----------------------------------------------------------------------
+const DNBRegisterSetInfo
+DNBArchImplI386::g_reg_sets[] =
+{
+ { "i386 Registers", NULL, k_num_all_registers },
+ { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers },
+ { "Floating Point Registers", g_fpu_registers, k_num_fpu_registers },
+ { "Exception State Registers", g_exc_registers, k_num_exc_registers }
+};
+// Total number of register sets for this architecture
+const size_t DNBArchImplI386::k_num_register_sets = sizeof(g_reg_sets)/sizeof(DNBRegisterSetInfo);
+
+
+const DNBRegisterSetInfo *
+DNBArchImplI386::GetRegisterSetInfo(nub_size_t *num_reg_sets)
+{
+ *num_reg_sets = k_num_register_sets;
+ return g_reg_sets;
+}
+
+bool
+DNBArchImplI386::GetRegisterValue(int set, int reg, DNBRegisterValue *value)
+{
+ if (set == REGISTER_SET_GENERIC)
+ {
+ switch (reg)
+ {
+ case GENERIC_REGNUM_PC: // Program Counter
+ set = e_regSetGPR;
+ reg = gpr_eip;
+ break;
+
+ case GENERIC_REGNUM_SP: // Stack Pointer
+ set = e_regSetGPR;
+ reg = gpr_esp;
+ break;
+
+ case GENERIC_REGNUM_FP: // Frame Pointer
+ set = e_regSetGPR;
+ reg = gpr_ebp;
+ break;
+
+ case GENERIC_REGNUM_FLAGS: // Processor flags register
+ set = e_regSetGPR;
+ reg = gpr_eflags;
+ break;
+
+ case GENERIC_REGNUM_RA: // Return Address
+ default:
+ return false;
+ }
+ }
+
+ if (GetRegisterState(set, false) != KERN_SUCCESS)
+ return false;
+
+ const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg);
+ if (regInfo)
+ {
+ value->info = *regInfo;
+ switch (set)
+ {
+ case e_regSetGPR:
+ if (reg < k_num_gpr_registers)
+ {
+ value->value.uint32 = ((uint32_t*)(&m_state.context.gpr))[reg];
+ return true;
+ }
+ break;
+
+ case e_regSetFPU:
+ switch (reg)
+ {
+ case fpu_fcw: value->value.uint16 = *((uint16_t *)(&m_state.context.fpu.__fpu_fcw)); return true;
+ case fpu_fsw: value->value.uint16 = *((uint16_t *)(&m_state.context.fpu.__fpu_fsw)); return true;
+ case fpu_ftw: value->value.uint8 = m_state.context.fpu.__fpu_ftw; return true;
+ case fpu_fop: value->value.uint16 = m_state.context.fpu.__fpu_fop; return true;
+ case fpu_ip: value->value.uint32 = m_state.context.fpu.__fpu_ip; return true;
+ case fpu_cs: value->value.uint16 = m_state.context.fpu.__fpu_cs; return true;
+ case fpu_dp: value->value.uint32 = m_state.context.fpu.__fpu_dp; return true;
+ case fpu_ds: value->value.uint16 = m_state.context.fpu.__fpu_ds; return true;
+ case fpu_mxcsr: value->value.uint32 = m_state.context.fpu.__fpu_mxcsr; return true;
+ case fpu_mxcsrmask: value->value.uint32 = m_state.context.fpu.__fpu_mxcsrmask; return true;
+
+ case fpu_stmm0: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_stmm0.__mmst_reg, 10); return true;
+ case fpu_stmm1: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_stmm1.__mmst_reg, 10); return true;
+ case fpu_stmm2: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_stmm2.__mmst_reg, 10); return true;
+ case fpu_stmm3: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_stmm3.__mmst_reg, 10); return true;
+ case fpu_stmm4: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_stmm4.__mmst_reg, 10); return true;
+ case fpu_stmm5: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_stmm5.__mmst_reg, 10); return true;
+ case fpu_stmm6: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_stmm6.__mmst_reg, 10); return true;
+ case fpu_stmm7: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_stmm7.__mmst_reg, 10); return true;
+
+ case fpu_xmm0: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_xmm0.__xmm_reg, 16); return true;
+ case fpu_xmm1: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_xmm1.__xmm_reg, 16); return true;
+ case fpu_xmm2: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_xmm2.__xmm_reg, 16); return true;
+ case fpu_xmm3: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_xmm3.__xmm_reg, 16); return true;
+ case fpu_xmm4: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_xmm4.__xmm_reg, 16); return true;
+ case fpu_xmm5: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_xmm5.__xmm_reg, 16); return true;
+ case fpu_xmm6: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_xmm6.__xmm_reg, 16); return true;
+ case fpu_xmm7: memcpy(&value->value.uint8, m_state.context.fpu.__fpu_xmm7.__xmm_reg, 16); return true;
+ }
+ break;
+
+ case e_regSetEXC:
+ if (reg < k_num_exc_registers)
+ {
+ value->value.uint32 = (&m_state.context.exc.__trapno)[reg];
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+
+bool
+DNBArchImplI386::SetRegisterValue(int set, int reg, const DNBRegisterValue *value)
+{
+ if (set == REGISTER_SET_GENERIC)
+ {
+ switch (reg)
+ {
+ case GENERIC_REGNUM_PC: // Program Counter
+ set = e_regSetGPR;
+ reg = gpr_eip;
+ break;
+
+ case GENERIC_REGNUM_SP: // Stack Pointer
+ set = e_regSetGPR;
+ reg = gpr_esp;
+ break;
+
+ case GENERIC_REGNUM_FP: // Frame Pointer
+ set = e_regSetGPR;
+ reg = gpr_ebp;
+ break;
+
+ case GENERIC_REGNUM_FLAGS: // Processor flags register
+ set = e_regSetGPR;
+ reg = gpr_eflags;
+ break;
+
+ case GENERIC_REGNUM_RA: // Return Address
+ default:
+ return false;
+ }
+ }
+
+ if (GetRegisterState(set, false) != KERN_SUCCESS)
+ return false;
+
+ bool success = false;
+ const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg);
+ if (regInfo)
+ {
+ switch (set)
+ {
+ case e_regSetGPR:
+ if (reg < k_num_gpr_registers)
+ {
+ ((uint32_t*)(&m_state.context.gpr))[reg] = value->value.uint32;
+ success = true;
+ }
+ break;
+
+ case e_regSetFPU:
+ switch (reg)
+ {
+ case fpu_fcw: *((uint16_t *)(&m_state.context.fpu.__fpu_fcw)) = value->value.uint16; success = true; break;
+ case fpu_fsw: *((uint16_t *)(&m_state.context.fpu.__fpu_fsw)) = value->value.uint16; success = true; break;
+ case fpu_ftw: m_state.context.fpu.__fpu_ftw = value->value.uint8; success = true; break;
+ case fpu_fop: m_state.context.fpu.__fpu_fop = value->value.uint16; success = true; break;
+ case fpu_ip: m_state.context.fpu.__fpu_ip = value->value.uint32; success = true; break;
+ case fpu_cs: m_state.context.fpu.__fpu_cs = value->value.uint16; success = true; break;
+ case fpu_dp: m_state.context.fpu.__fpu_dp = value->value.uint32; success = true; break;
+ case fpu_ds: m_state.context.fpu.__fpu_ds = value->value.uint16; success = true; break;
+ case fpu_mxcsr: m_state.context.fpu.__fpu_mxcsr = value->value.uint32; success = true; break;
+ case fpu_mxcsrmask: m_state.context.fpu.__fpu_mxcsrmask = value->value.uint32; success = true; break;
+
+ case fpu_stmm0: memcpy (m_state.context.fpu.__fpu_stmm0.__mmst_reg, &value->value.uint8, 10); success = true; break;
+ case fpu_stmm1: memcpy (m_state.context.fpu.__fpu_stmm1.__mmst_reg, &value->value.uint8, 10); success = true; break;
+ case fpu_stmm2: memcpy (m_state.context.fpu.__fpu_stmm2.__mmst_reg, &value->value.uint8, 10); success = true; break;
+ case fpu_stmm3: memcpy (m_state.context.fpu.__fpu_stmm3.__mmst_reg, &value->value.uint8, 10); success = true; break;
+ case fpu_stmm4: memcpy (m_state.context.fpu.__fpu_stmm4.__mmst_reg, &value->value.uint8, 10); success = true; break;
+ case fpu_stmm5: memcpy (m_state.context.fpu.__fpu_stmm5.__mmst_reg, &value->value.uint8, 10); success = true; break;
+ case fpu_stmm6: memcpy (m_state.context.fpu.__fpu_stmm6.__mmst_reg, &value->value.uint8, 10); success = true; break;
+ case fpu_stmm7: memcpy (m_state.context.fpu.__fpu_stmm7.__mmst_reg, &value->value.uint8, 10); success = true; break;
+
+ case fpu_xmm0: memcpy(m_state.context.fpu.__fpu_xmm0.__xmm_reg, &value->value.uint8, 16); success = true; break;
+ case fpu_xmm1: memcpy(m_state.context.fpu.__fpu_xmm1.__xmm_reg, &value->value.uint8, 16); success = true; break;
+ case fpu_xmm2: memcpy(m_state.context.fpu.__fpu_xmm2.__xmm_reg, &value->value.uint8, 16); success = true; break;
+ case fpu_xmm3: memcpy(m_state.context.fpu.__fpu_xmm3.__xmm_reg, &value->value.uint8, 16); success = true; break;
+ case fpu_xmm4: memcpy(m_state.context.fpu.__fpu_xmm4.__xmm_reg, &value->value.uint8, 16); success = true; break;
+ case fpu_xmm5: memcpy(m_state.context.fpu.__fpu_xmm5.__xmm_reg, &value->value.uint8, 16); success = true; break;
+ case fpu_xmm6: memcpy(m_state.context.fpu.__fpu_xmm6.__xmm_reg, &value->value.uint8, 16); success = true; break;
+ case fpu_xmm7: memcpy(m_state.context.fpu.__fpu_xmm7.__xmm_reg, &value->value.uint8, 16); success = true; break;
+ }
+ break;
+
+ case e_regSetEXC:
+ if (reg < k_num_exc_registers)
+ {
+ (&m_state.context.exc.__trapno)[reg] = value->value.uint32;
+ success = true;
+ }
+ break;
+ }
+ }
+
+ if (success)
+ return SetRegisterState(set) == KERN_SUCCESS;
+ return false;
+}
+
+
+nub_size_t
+DNBArchImplI386::GetRegisterContext (void *buf, nub_size_t buf_len)
+{
+ nub_size_t size = sizeof (m_state.context);
+
+ if (buf && buf_len)
+ {
+ if (size > buf_len)
+ size = buf_len;
+
+ bool force = false;
+ if (GetGPRState(force) | GetFPUState(force) | GetEXCState(force))
+ return 0;
+ ::memcpy (buf, &m_state.context, size);
+ }
+ DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::GetRegisterContext (buf = %p, len = %zu) => %zu", buf, buf_len, size);
+ // Return the size of the register context even if NULL was passed in
+ return size;
+}
+
+nub_size_t
+DNBArchImplI386::SetRegisterContext (const void *buf, nub_size_t buf_len)
+{
+ nub_size_t size = sizeof (m_state.context);
+ if (buf == NULL || buf_len == 0)
+ size = 0;
+
+ if (size)
+ {
+ if (size > buf_len)
+ size = buf_len;
+
+ ::memcpy (&m_state.context, buf, size);
+ SetGPRState();
+ SetFPUState();
+ SetEXCState();
+ }
+ DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::SetRegisterContext (buf = %p, len = %zu) => %zu", buf, buf_len, size);
+ return size;
+}
+
+
+
+kern_return_t
+DNBArchImplI386::GetRegisterState(int set, bool force)
+{
+ switch (set)
+ {
+ case e_regSetALL: return GetGPRState(force) | GetFPUState(force) | GetEXCState(force);
+ case e_regSetGPR: return GetGPRState(force);
+ case e_regSetFPU: return GetFPUState(force);
+ case e_regSetEXC: return GetEXCState(force);
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+kern_return_t
+DNBArchImplI386::SetRegisterState(int set)
+{
+ // Make sure we have a valid context to set.
+ if (RegisterSetStateIsValid(set))
+ {
+ switch (set)
+ {
+ case e_regSetALL: return SetGPRState() | SetFPUState() | SetEXCState();
+ case e_regSetGPR: return SetGPRState();
+ case e_regSetFPU: return SetFPUState();
+ case e_regSetEXC: return SetEXCState();
+ default: break;
+ }
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+bool
+DNBArchImplI386::RegisterSetStateIsValid (int set) const
+{
+ return m_state.RegsAreValid(set);
+}
+
+
+
+#endif // #if defined (__i386__)
diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h
new file mode 100644
index 00000000000..10972c24ca5
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h
@@ -0,0 +1,196 @@
+//===-- DNBArchImplI386.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/25/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DNBArchImplI386_h__
+#define __DNBArchImplI386_h__
+
+#if defined (__i386__)
+
+#include "DNBArch.h"
+#include <mach/mach_types.h>
+#include <mach/thread_status.h>
+
+
+class MachThread;
+
+class DNBArchImplI386 : public DNBArchProtocol
+{
+public:
+ DNBArchImplI386(MachThread *thread) :
+ m_thread(thread),
+ m_state()
+ {
+ }
+ virtual ~DNBArchImplI386()
+ {
+ }
+
+ static const DNBRegisterSetInfo *
+ GetRegisterSetInfo(nub_size_t *num_reg_sets);
+
+ virtual bool GetRegisterValue(int set, int reg, DNBRegisterValue *reg);
+ virtual bool SetRegisterValue(int set, int reg, const DNBRegisterValue *reg);
+ virtual nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len);
+ virtual nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len);
+ virtual kern_return_t GetRegisterState (int set, bool force);
+ virtual kern_return_t SetRegisterState (int set);
+ virtual bool RegisterSetStateIsValid (int set) const;
+
+ virtual uint64_t GetPC(uint64_t failValue); // Get program counter
+ virtual kern_return_t SetPC(uint64_t value);
+ virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer
+ virtual void ThreadWillResume();
+ virtual bool ThreadDidStop();
+ virtual bool NotifyException(MachException::Data& exc);
+
+ static const uint8_t * const SoftwareBreakpointOpcode (nub_size_t byte_size);
+ static uint32_t GetCPUType();
+
+protected:
+ kern_return_t EnableHardwareSingleStep (bool enable);
+
+ typedef i386_thread_state_t GPR;
+ typedef i386_float_state_t FPU;
+ typedef i386_exception_state_t EXC;
+
+ static const DNBRegisterInfo g_gpr_registers[];
+ static const DNBRegisterInfo g_fpu_registers[];
+ static const DNBRegisterInfo g_exc_registers[];
+ static const DNBRegisterSetInfo g_reg_sets[];
+ static const size_t k_num_gpr_registers;
+ static const size_t k_num_fpu_registers;
+ static const size_t k_num_exc_registers;
+ static const size_t k_num_all_registers;
+ static const size_t k_num_register_sets;
+
+ typedef enum RegisterSetTag
+ {
+ e_regSetALL = REGISTER_SET_ALL,
+ e_regSetGPR,
+ e_regSetFPU,
+ e_regSetEXC,
+ kNumRegisterSets
+ } RegisterSet;
+
+ typedef enum RegisterSetWordSizeTag
+ {
+ e_regSetWordSizeGPR = i386_THREAD_STATE_COUNT,
+ e_regSetWordSizeFPR = i386_FLOAT_STATE_COUNT,
+ e_regSetWordSizeEXC = i386_EXCEPTION_STATE_COUNT
+ } RegisterSetWordSize;
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ struct Context
+ {
+ i386_thread_state_t gpr;
+ i386_float_state_t fpu;
+ i386_exception_state_t exc;
+ };
+
+ struct State
+ {
+ Context context;
+ kern_return_t gpr_errs[2]; // Read/Write errors
+ kern_return_t fpu_errs[2]; // Read/Write errors
+ kern_return_t exc_errs[2]; // Read/Write errors
+
+ State()
+ {
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+ }
+ void InvalidateAllRegisterStates()
+ {
+ SetError (e_regSetALL, Read, -1);
+ }
+ kern_return_t 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 e_regSetALL: return gpr_errs[err_idx] |
+ fpu_errs[err_idx] |
+ exc_errs[err_idx];
+ case e_regSetGPR: return gpr_errs[err_idx];
+ case e_regSetFPU: return fpu_errs[err_idx];
+ case e_regSetEXC: return exc_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+ bool SetError (int flavor, uint32_t err_idx, kern_return_t err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case e_regSetALL:
+ gpr_errs[err_idx] =
+ fpu_errs[err_idx] =
+ exc_errs[err_idx] = err;
+ return true;
+
+ case e_regSetGPR:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case e_regSetFPU:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case e_regSetEXC:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+ bool RegsAreValid (int flavor) const
+ {
+ return GetError(flavor, Read) == KERN_SUCCESS;
+ }
+ };
+
+ kern_return_t GetGPRState (bool force);
+ kern_return_t GetFPUState (bool force);
+ kern_return_t GetEXCState (bool force);
+
+ kern_return_t SetGPRState ();
+ kern_return_t SetFPUState ();
+ kern_return_t SetEXCState ();
+
+ MachThread *m_thread;
+ State m_state;
+};
+
+typedef DNBArchImplI386 DNBArch;
+
+#endif // #if defined (__i386__)
+#endif // #ifndef __DNBArchImplI386_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp b/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp
new file mode 100644
index 00000000000..abd1a353158
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp
@@ -0,0 +1,569 @@
+//===-- DNBArchImpl.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/25/07.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
+
+#if __DARWIN_UNIX03
+#define PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(reg) __##reg
+#else
+#define PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(reg) reg
+#endif
+
+#include "MacOSX/ppc/DNBArchImpl.h"
+#include "MacOSX/MachThread.h"
+#include "DNBBreakpoint.h"
+#include "DNBLog.h"
+#include "DNBRegisterInfo.h"
+
+static const uint8_t g_breakpoint_opcode[] = { 0x7F, 0xC0, 0x00, 0x08 };
+
+const uint8_t * const
+DNBArchMachPPC::SoftwareBreakpointOpcode (nub_size_t size)
+{
+ if (size == 4)
+ return g_breakpoint_opcode;
+ return NULL;
+}
+
+uint32_t
+DNBArchMachPPC::GetCPUType()
+{
+ return CPU_TYPE_POWERPC;
+}
+
+uint64_t
+DNBArchMachPPC::GetPC(uint64_t failValue)
+{
+ // Get program counter
+ if (GetGPRState(false) == KERN_SUCCESS)
+ return m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr0);
+ return failValue;
+}
+
+kern_return_t
+DNBArchMachPPC::SetPC(uint64_t value)
+{
+ // Get program counter
+ kern_return_t err = GetGPRState(false);
+ if (err == KERN_SUCCESS)
+ {
+ m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr0) = value;
+ err = SetGPRState();
+ }
+ return err == KERN_SUCCESS;
+}
+
+uint64_t
+DNBArchMachPPC::GetSP(uint64_t failValue)
+{
+ // Get stack pointer
+ if (GetGPRState(false) == KERN_SUCCESS)
+ return m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(r1);
+ return failValue;
+}
+
+kern_return_t
+DNBArchMachPPC::GetGPRState(bool force)
+{
+ if (force || m_state.GetError(e_regSetGPR, Read))
+ {
+ mach_msg_type_number_t count = e_regSetWordSizeGPR;
+ m_state.SetError(e_regSetGPR, Read, ::thread_get_state(m_thread->ThreadID(), e_regSetGPR, (thread_state_t)&m_state.gpr, &count));
+ }
+ return m_state.GetError(e_regSetGPR, Read);
+}
+
+kern_return_t
+DNBArchMachPPC::GetFPRState(bool force)
+{
+ if (force || m_state.GetError(e_regSetFPR, Read))
+ {
+ mach_msg_type_number_t count = e_regSetWordSizeFPR;
+ m_state.SetError(e_regSetFPR, Read, ::thread_get_state(m_thread->ThreadID(), e_regSetFPR, (thread_state_t)&m_state.fpr, &count));
+ }
+ return m_state.GetError(e_regSetFPR, Read);
+}
+
+kern_return_t
+DNBArchMachPPC::GetEXCState(bool force)
+{
+ if (force || m_state.GetError(e_regSetEXC, Read))
+ {
+ mach_msg_type_number_t count = e_regSetWordSizeEXC;
+ m_state.SetError(e_regSetEXC, Read, ::thread_get_state(m_thread->ThreadID(), e_regSetEXC, (thread_state_t)&m_state.exc, &count));
+ }
+ return m_state.GetError(e_regSetEXC, Read);
+}
+
+kern_return_t
+DNBArchMachPPC::GetVECState(bool force)
+{
+ if (force || m_state.GetError(e_regSetVEC, Read))
+ {
+ mach_msg_type_number_t count = e_regSetWordSizeVEC;
+ m_state.SetError(e_regSetVEC, Read, ::thread_get_state(m_thread->ThreadID(), e_regSetVEC, (thread_state_t)&m_state.vec, &count));
+ }
+ return m_state.GetError(e_regSetVEC, Read);
+}
+
+kern_return_t
+DNBArchMachPPC::SetGPRState()
+{
+ m_state.SetError(e_regSetGPR, Write, ::thread_set_state(m_thread->ThreadID(), e_regSetGPR, (thread_state_t)&m_state.gpr, e_regSetWordSizeGPR));
+ return m_state.GetError(e_regSetGPR, Write);
+}
+
+kern_return_t
+DNBArchMachPPC::SetFPRState()
+{
+ m_state.SetError(e_regSetFPR, Write, ::thread_set_state(m_thread->ThreadID(), e_regSetFPR, (thread_state_t)&m_state.fpr, e_regSetWordSizeFPR));
+ return m_state.GetError(e_regSetFPR, Write);
+}
+
+kern_return_t
+DNBArchMachPPC::SetEXCState()
+{
+ m_state.SetError(e_regSetEXC, Write, ::thread_set_state(m_thread->ThreadID(), e_regSetEXC, (thread_state_t)&m_state.exc, e_regSetWordSizeEXC));
+ return m_state.GetError(e_regSetEXC, Write);
+}
+
+kern_return_t
+DNBArchMachPPC::SetVECState()
+{
+ m_state.SetError(e_regSetVEC, Write, ::thread_set_state(m_thread->ThreadID(), e_regSetVEC, (thread_state_t)&m_state.vec, e_regSetWordSizeVEC));
+ return m_state.GetError(e_regSetVEC, Write);
+}
+
+bool
+DNBArchMachPPC::ThreadWillResume()
+{
+ bool success = true;
+
+ // Do we need to step this thread? If so, let the mach thread tell us so.
+ if (m_thread->IsStepping())
+ {
+ // This is the primary thread, let the arch do anything it needs
+ success = EnableHardwareSingleStep(true) == KERN_SUCCESS;
+ }
+ return success;
+}
+
+bool
+DNBArchMachPPC::ThreadDidStop()
+{
+ bool success = true;
+
+ m_state.InvalidateAllRegisterStates();
+
+ // Are we stepping a single instruction?
+ if (GetGPRState(true) == KERN_SUCCESS)
+ {
+ // We are single stepping, was this the primary thread?
+ if (m_thread->IsStepping())
+ {
+ // This was the primary thread, we need to clear the trace
+ // bit if so.
+ success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
+ }
+ else
+ {
+ // The MachThread will automatically restore the suspend count
+ // in ThreadDidStop(), so we don't need to do anything here if
+ // we weren't the primary thread the last time
+ }
+ }
+ return success;
+}
+
+
+// Set the single step bit in the processor status register.
+kern_return_t
+DNBArchMachPPC::EnableHardwareSingleStep (bool enable)
+{
+ DNBLogThreadedIf(LOG_STEP, "DNBArchMachPPC::EnableHardwareSingleStep( enable = %d )", enable);
+ if (GetGPRState(false) == KERN_SUCCESS)
+ {
+ const uint32_t trace_bit = 0x400;
+ if (enable)
+ m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr1) |= trace_bit;
+ else
+ m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr1) &= ~trace_bit;
+ return SetGPRState();
+ }
+ return m_state.GetError(e_regSetGPR, Read);
+}
+
+//----------------------------------------------------------------------
+// Register information defintions for 32 bit PowerPC.
+//----------------------------------------------------------------------
+
+enum gpr_regnums
+{
+ e_regNumGPR_srr0,
+ e_regNumGPR_srr1,
+ e_regNumGPR_r0,
+ e_regNumGPR_r1,
+ e_regNumGPR_r2,
+ e_regNumGPR_r3,
+ e_regNumGPR_r4,
+ e_regNumGPR_r5,
+ e_regNumGPR_r6,
+ e_regNumGPR_r7,
+ e_regNumGPR_r8,
+ e_regNumGPR_r9,
+ e_regNumGPR_r10,
+ e_regNumGPR_r11,
+ e_regNumGPR_r12,
+ e_regNumGPR_r13,
+ e_regNumGPR_r14,
+ e_regNumGPR_r15,
+ e_regNumGPR_r16,
+ e_regNumGPR_r17,
+ e_regNumGPR_r18,
+ e_regNumGPR_r19,
+ e_regNumGPR_r20,
+ e_regNumGPR_r21,
+ e_regNumGPR_r22,
+ e_regNumGPR_r23,
+ e_regNumGPR_r24,
+ e_regNumGPR_r25,
+ e_regNumGPR_r26,
+ e_regNumGPR_r27,
+ e_regNumGPR_r28,
+ e_regNumGPR_r29,
+ e_regNumGPR_r30,
+ e_regNumGPR_r31,
+ e_regNumGPR_cr,
+ e_regNumGPR_xer,
+ e_regNumGPR_lr,
+ e_regNumGPR_ctr,
+ e_regNumGPR_mq,
+ e_regNumGPR_vrsave
+};
+
+
+
+
+// General purpose registers
+static DNBRegisterInfo g_gpr_registers[] =
+{
+ { "srr0" , Uint, 4, Hex },
+ { "srr1" , Uint, 4, Hex },
+ { "r0" , Uint, 4, Hex },
+ { "r1" , Uint, 4, Hex },
+ { "r2" , Uint, 4, Hex },
+ { "r3" , Uint, 4, Hex },
+ { "r4" , Uint, 4, Hex },
+ { "r5" , Uint, 4, Hex },
+ { "r6" , Uint, 4, Hex },
+ { "r7" , Uint, 4, Hex },
+ { "r8" , Uint, 4, Hex },
+ { "r9" , Uint, 4, Hex },
+ { "r10" , Uint, 4, Hex },
+ { "r11" , Uint, 4, Hex },
+ { "r12" , Uint, 4, Hex },
+ { "r13" , Uint, 4, Hex },
+ { "r14" , Uint, 4, Hex },
+ { "r15" , Uint, 4, Hex },
+ { "r16" , Uint, 4, Hex },
+ { "r17" , Uint, 4, Hex },
+ { "r18" , Uint, 4, Hex },
+ { "r19" , Uint, 4, Hex },
+ { "r20" , Uint, 4, Hex },
+ { "r21" , Uint, 4, Hex },
+ { "r22" , Uint, 4, Hex },
+ { "r23" , Uint, 4, Hex },
+ { "r24" , Uint, 4, Hex },
+ { "r25" , Uint, 4, Hex },
+ { "r26" , Uint, 4, Hex },
+ { "r27" , Uint, 4, Hex },
+ { "r28" , Uint, 4, Hex },
+ { "r29" , Uint, 4, Hex },
+ { "r30" , Uint, 4, Hex },
+ { "r31" , Uint, 4, Hex },
+ { "cr" , Uint, 4, Hex },
+ { "xer" , Uint, 4, Hex },
+ { "lr" , Uint, 4, Hex },
+ { "ctr" , Uint, 4, Hex },
+ { "mq" , Uint, 4, Hex },
+ { "vrsave", Uint, 4, Hex },
+};
+
+// Floating point registers
+static DNBRegisterInfo g_fpr_registers[] =
+{
+ { "fp0" , IEEE754, 8, Float },
+ { "fp1" , IEEE754, 8, Float },
+ { "fp2" , IEEE754, 8, Float },
+ { "fp3" , IEEE754, 8, Float },
+ { "fp4" , IEEE754, 8, Float },
+ { "fp5" , IEEE754, 8, Float },
+ { "fp6" , IEEE754, 8, Float },
+ { "fp7" , IEEE754, 8, Float },
+ { "fp8" , IEEE754, 8, Float },
+ { "fp9" , IEEE754, 8, Float },
+ { "fp10" , IEEE754, 8, Float },
+ { "fp11" , IEEE754, 8, Float },
+ { "fp12" , IEEE754, 8, Float },
+ { "fp13" , IEEE754, 8, Float },
+ { "fp14" , IEEE754, 8, Float },
+ { "fp15" , IEEE754, 8, Float },
+ { "fp16" , IEEE754, 8, Float },
+ { "fp17" , IEEE754, 8, Float },
+ { "fp18" , IEEE754, 8, Float },
+ { "fp19" , IEEE754, 8, Float },
+ { "fp20" , IEEE754, 8, Float },
+ { "fp21" , IEEE754, 8, Float },
+ { "fp22" , IEEE754, 8, Float },
+ { "fp23" , IEEE754, 8, Float },
+ { "fp24" , IEEE754, 8, Float },
+ { "fp25" , IEEE754, 8, Float },
+ { "fp26" , IEEE754, 8, Float },
+ { "fp27" , IEEE754, 8, Float },
+ { "fp28" , IEEE754, 8, Float },
+ { "fp29" , IEEE754, 8, Float },
+ { "fp30" , IEEE754, 8, Float },
+ { "fp31" , IEEE754, 8, Float },
+ { "fpscr" , Uint, 4, Hex }
+};
+
+// Exception registers
+
+static DNBRegisterInfo g_exc_registers[] =
+{
+ { "dar" , Uint, 4, Hex },
+ { "dsisr" , Uint, 4, Hex },
+ { "exception" , Uint, 4, Hex }
+};
+
+// Altivec registers
+static DNBRegisterInfo g_vec_registers[] =
+{
+ { "vr0" , Vector, 16, VectorOfFloat32 },
+ { "vr1" , Vector, 16, VectorOfFloat32 },
+ { "vr2" , Vector, 16, VectorOfFloat32 },
+ { "vr3" , Vector, 16, VectorOfFloat32 },
+ { "vr4" , Vector, 16, VectorOfFloat32 },
+ { "vr5" , Vector, 16, VectorOfFloat32 },
+ { "vr6" , Vector, 16, VectorOfFloat32 },
+ { "vr7" , Vector, 16, VectorOfFloat32 },
+ { "vr8" , Vector, 16, VectorOfFloat32 },
+ { "vr9" , Vector, 16, VectorOfFloat32 },
+ { "vr10" , Vector, 16, VectorOfFloat32 },
+ { "vr11" , Vector, 16, VectorOfFloat32 },
+ { "vr12" , Vector, 16, VectorOfFloat32 },
+ { "vr13" , Vector, 16, VectorOfFloat32 },
+ { "vr14" , Vector, 16, VectorOfFloat32 },
+ { "vr15" , Vector, 16, VectorOfFloat32 },
+ { "vr16" , Vector, 16, VectorOfFloat32 },
+ { "vr17" , Vector, 16, VectorOfFloat32 },
+ { "vr18" , Vector, 16, VectorOfFloat32 },
+ { "vr19" , Vector, 16, VectorOfFloat32 },
+ { "vr20" , Vector, 16, VectorOfFloat32 },
+ { "vr21" , Vector, 16, VectorOfFloat32 },
+ { "vr22" , Vector, 16, VectorOfFloat32 },
+ { "vr23" , Vector, 16, VectorOfFloat32 },
+ { "vr24" , Vector, 16, VectorOfFloat32 },
+ { "vr25" , Vector, 16, VectorOfFloat32 },
+ { "vr26" , Vector, 16, VectorOfFloat32 },
+ { "vr27" , Vector, 16, VectorOfFloat32 },
+ { "vr28" , Vector, 16, VectorOfFloat32 },
+ { "vr29" , Vector, 16, VectorOfFloat32 },
+ { "vr30" , Vector, 16, VectorOfFloat32 },
+ { "vr31" , Vector, 16, VectorOfFloat32 },
+ { "vscr" , Uint, 16, Hex },
+ { "vrvalid" , Uint, 4, Hex }
+};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = sizeof(g_gpr_registers)/sizeof(DNBRegisterInfo);
+const size_t k_num_fpr_registers = sizeof(g_fpr_registers)/sizeof(DNBRegisterInfo);
+const size_t k_num_exc_registers = sizeof(g_exc_registers)/sizeof(DNBRegisterInfo);
+const size_t k_num_vec_registers = sizeof(g_vec_registers)/sizeof(DNBRegisterInfo);
+// Total number of registers for this architecture
+const size_t k_num_ppc_registers = k_num_gpr_registers + k_num_fpr_registers + k_num_exc_registers + k_num_vec_registers;
+
+//----------------------------------------------------------------------
+// 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 DNBRegisterSetInfo g_reg_sets[] =
+{
+ { "PowerPC Registers", NULL, k_num_ppc_registers },
+ { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers },
+ { "Floating Point Registers", g_fpr_registers, k_num_fpr_registers },
+ { "Exception State Registers", g_exc_registers, k_num_exc_registers },
+ { "Altivec Registers", g_vec_registers, k_num_vec_registers }
+};
+// Total number of register sets for this architecture
+const size_t k_num_register_sets = sizeof(g_reg_sets)/sizeof(DNBRegisterSetInfo);
+
+
+const DNBRegisterSetInfo *
+DNBArchMachPPC::GetRegisterSetInfo(nub_size_t *num_reg_sets) const
+{
+ *num_reg_sets = k_num_register_sets;
+ return g_reg_sets;
+}
+
+bool
+DNBArchMachPPC::GetRegisterValue(int set, int reg, DNBRegisterValue *value) const
+{
+ if (set == REGISTER_SET_GENERIC)
+ {
+ switch (reg)
+ {
+ case GENERIC_REGNUM_PC: // Program Counter
+ set = e_regSetGPR;
+ reg = e_regNumGPR_srr0;
+ break;
+
+ case GENERIC_REGNUM_SP: // Stack Pointer
+ set = e_regSetGPR;
+ reg = e_regNumGPR_r1;
+ break;
+
+ case GENERIC_REGNUM_FP: // Frame Pointer
+ // Return false for now instead of returning r30 as gcc 3.x would
+ // use a variety of registers for the FP and it takes inspecting
+ // the stack to make sure there is a frame pointer before we can
+ // determine the FP.
+ return false;
+
+ case GENERIC_REGNUM_RA: // Return Address
+ set = e_regSetGPR;
+ reg = e_regNumGPR_lr;
+ break;
+
+ case GENERIC_REGNUM_FLAGS: // Processor flags register
+ set = e_regSetGPR;
+ reg = e_regNumGPR_srr1;
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ if (!m_state.RegsAreValid(set))
+ return false;
+
+ const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg);
+ if (regInfo)
+ {
+ value->info = *regInfo;
+ switch (set)
+ {
+ case e_regSetGPR:
+ if (reg < k_num_gpr_registers)
+ {
+ value->value.uint32 = (&m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr0))[reg];
+ return true;
+ }
+ break;
+
+ case e_regSetFPR:
+ if (reg < 32)
+ {
+ value->value.float64 = m_state.fpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(fpregs)[reg];
+ return true;
+ }
+ else if (reg == 32)
+ {
+ value->value.uint32 = m_state.fpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(fpscr);
+ return true;
+ }
+ break;
+
+ case e_regSetEXC:
+ if (reg < k_num_exc_registers)
+ {
+ value->value.uint32 = (&m_state.exc.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(dar))[reg];
+ return true;
+ }
+ break;
+
+ case e_regSetVEC:
+ if (reg < k_num_vec_registers)
+ {
+ if (reg < 33) // FP0 - FP31 and VSCR
+ {
+ // Copy all 4 uint32 values for this vector register
+ value->value.v_uint32[0] = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg][0];
+ value->value.v_uint32[1] = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg][1];
+ value->value.v_uint32[2] = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg][2];
+ value->value.v_uint32[3] = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg][3];
+ return true;
+ }
+ else if (reg == 34) // VRVALID
+ {
+ value->value.uint32 = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vrvalid);
+ return true;
+ }
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+
+kern_return_t
+DNBArchMachPPC::GetRegisterState(int set, bool force)
+{
+ switch (set)
+ {
+ case e_regSetALL:
+ return GetGPRState(force) |
+ GetFPRState(force) |
+ GetEXCState(force) |
+ GetVECState(force);
+ case e_regSetGPR: return GetGPRState(force);
+ case e_regSetFPR: return GetFPRState(force);
+ case e_regSetEXC: return GetEXCState(force);
+ case e_regSetVEC: return GetVECState(force);
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+kern_return_t
+DNBArchMachPPC::SetRegisterState(int set)
+{
+ // Make sure we have a valid context to set.
+ kern_return_t err = GetRegisterState(set, false);
+ if (err != KERN_SUCCESS)
+ return err;
+
+ switch (set)
+ {
+ case e_regSetALL: return SetGPRState() | SetFPRState() | SetEXCState() | SetVECState();
+ case e_regSetGPR: return SetGPRState();
+ case e_regSetFPR: return SetFPRState();
+ case e_regSetEXC: return SetEXCState();
+ case e_regSetVEC: return SetVECState();
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+bool
+DNBArchMachPPC::RegisterSetStateIsValid (int set) const
+{
+ return m_state.RegsAreValid(set);
+}
+
+
+#endif // #if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
+
diff --git a/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.h b/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.h
new file mode 100644
index 00000000000..6263407460a
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.h
@@ -0,0 +1,180 @@
+//===-- DNBArchImpl.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/25/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DebugNubArchMachPPC_h__
+#define __DebugNubArchMachPPC_h__
+
+#if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
+
+#include "DNBArch.h"
+
+class MachThread;
+
+class DNBArchMachPPC : public DNBArchProtocol
+{
+public:
+ DNBArchMachPPC(MachThread *thread) :
+ m_thread(thread),
+ m_state()
+ {
+ }
+
+ virtual ~DNBArchMachPPC()
+ {
+ }
+
+ virtual const DNBRegisterSetInfo *
+ GetRegisterSetInfo(nub_size_t *num_reg_sets) const;
+ virtual bool GetRegisterValue(int set, int reg, DNBRegisterValue *value) const;
+ virtual kern_return_t GetRegisterState (int set, bool force);
+ virtual kern_return_t SetRegisterState (int set);
+ virtual bool RegisterSetStateIsValid (int set) const;
+
+ virtual uint64_t GetPC(uint64_t failValue); // Get program counter
+ virtual kern_return_t SetPC(uint64_t value);
+ virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer
+ virtual bool ThreadWillResume();
+ virtual bool ThreadDidStop();
+
+ static const uint8_t * const SoftwareBreakpointOpcode (nub_size_t byte_size);
+ static uint32_t GetCPUType();
+
+protected:
+
+
+ kern_return_t EnableHardwareSingleStep (bool enable);
+
+ typedef enum RegisterSetTag
+ {
+ e_regSetALL = REGISTER_SET_ALL,
+ e_regSetGPR,
+ e_regSetFPR,
+ e_regSetEXC,
+ e_regSetVEC,
+ kNumRegisterSets
+ } RegisterSet;
+
+ typedef enum RegisterSetWordSizeTag
+ {
+ e_regSetWordSizeGPR = PPC_THREAD_STATE_COUNT,
+ e_regSetWordSizeFPR = PPC_FLOAT_STATE_COUNT,
+ e_regSetWordSizeEXC = PPC_EXCEPTION_STATE_COUNT,
+ e_regSetWordSizeVEC = PPC_VECTOR_STATE_COUNT
+ } RegisterSetWordSize;
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ struct State
+ {
+ ppc_thread_state_t gpr;
+ ppc_float_state_t fpr;
+ ppc_exception_state_t exc;
+ ppc_vector_state_t vec;
+ kern_return_t gpr_errs[2]; // Read/Write errors
+ kern_return_t fpr_errs[2]; // Read/Write errors
+ kern_return_t exc_errs[2]; // Read/Write errors
+ kern_return_t vec_errs[2]; // Read/Write errors
+
+ State()
+ {
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpr_errs[i] = -1;
+ exc_errs[i] = -1;
+ vec_errs[i] = -1;
+ }
+ }
+ void InvalidateAllRegisterStates()
+ {
+ SetError (e_regSetALL, Read, -1);
+ }
+ kern_return_t GetError (int set, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (set)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case e_regSetALL: return gpr_errs[err_idx] | fpr_errs[err_idx] | exc_errs[err_idx] | vec_errs[err_idx];
+ case e_regSetGPR: return gpr_errs[err_idx];
+ case e_regSetFPR: return fpr_errs[err_idx];
+ case e_regSetEXC: return exc_errs[err_idx];
+ case e_regSetVEC: return vec_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+ bool SetError (int set, uint32_t err_idx, kern_return_t err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (set)
+ {
+ case e_regSetALL:
+ gpr_errs[err_idx] = fpr_errs[err_idx] = exc_errs[err_idx] = vec_errs[err_idx] = err;
+ return true;
+
+ case e_regSetGPR:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case e_regSetFPR:
+ fpr_errs[err_idx] = err;
+ return true;
+
+ case e_regSetEXC:
+ exc_errs[err_idx] = err;
+ return true;
+
+ case e_regSetVEC:
+ vec_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+ bool RegsAreValid (int set) const
+ {
+ return GetError(set, Read) == KERN_SUCCESS;
+ }
+ };
+
+ kern_return_t GetGPRState (bool force);
+ kern_return_t GetFPRState (bool force);
+ kern_return_t GetEXCState (bool force);
+ kern_return_t GetVECState (bool force);
+
+ kern_return_t SetGPRState ();
+ kern_return_t SetFPRState ();
+ kern_return_t SetEXCState ();
+ kern_return_t SetVECState ();
+
+protected:
+ MachThread * m_thread;
+ State m_state;
+};
+
+typedef DNBArchMachPPC DNBArch;
+#endif // #if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
+#endif // #ifndef __DebugNubArchMachPPC_h__
diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
new file mode 100644
index 00000000000..1f18156650c
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
@@ -0,0 +1,1035 @@
+//===-- DNBArchImplX86_64.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/25/07.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined (__x86_64__)
+
+#include <sys/cdefs.h>
+
+#include "MacOSX/x86_64/DNBArchImplX86_64.h"
+#include "DNBLog.h"
+#include "MachThread.h"
+#include "MachProcess.h"
+
+static const uint8_t g_breakpoint_opcode[] = { 0xCC };
+
+const uint8_t * const
+DNBArchImplX86_64::SoftwareBreakpointOpcode (nub_size_t byte_size)
+{
+ if (byte_size == 1)
+ return g_breakpoint_opcode;
+ return NULL;
+}
+
+uint32_t
+DNBArchImplX86_64::GetCPUType()
+{
+ return CPU_TYPE_X86_64;
+}
+
+uint64_t
+DNBArchImplX86_64::GetPC(uint64_t failValue)
+{
+ // Get program counter
+ if (GetGPRState(false) == KERN_SUCCESS)
+ return m_state.context.gpr.__rip;
+ return failValue;
+}
+
+kern_return_t
+DNBArchImplX86_64::SetPC(uint64_t value)
+{
+ // Get program counter
+ kern_return_t err = GetGPRState(false);
+ if (err == KERN_SUCCESS)
+ {
+ m_state.context.gpr.__rip = value;
+ err = SetGPRState();
+ }
+ return err == KERN_SUCCESS;
+}
+
+uint64_t
+DNBArchImplX86_64::GetSP(uint64_t failValue)
+{
+ // Get stack pointer
+ if (GetGPRState(false) == KERN_SUCCESS)
+ return m_state.context.gpr.__rsp;
+ return failValue;
+}
+
+// Uncomment the value below to verify the values in the debugger.
+//#define DEBUG_GPR_VALUES 1 // DO NOT CHECK IN WITH THIS DEFINE ENABLED
+
+kern_return_t
+DNBArchImplX86_64::GetGPRState(bool force)
+{
+ if (force || m_state.GetError(e_regSetGPR, Read))
+ {
+#if DEBUG_GPR_VALUES
+ m_state.context.gpr.__rax = ('a' << 8) + 'x';
+ m_state.context.gpr.__rbx = ('b' << 8) + 'x';
+ m_state.context.gpr.__rcx = ('c' << 8) + 'x';
+ m_state.context.gpr.__rdx = ('d' << 8) + 'x';
+ m_state.context.gpr.__rdi = ('d' << 8) + 'i';
+ m_state.context.gpr.__rsi = ('s' << 8) + 'i';
+ m_state.context.gpr.__rbp = ('b' << 8) + 'p';
+ m_state.context.gpr.__rsp = ('s' << 8) + 'p';
+ m_state.context.gpr.__r8 = ('r' << 8) + '8';
+ m_state.context.gpr.__r9 = ('r' << 8) + '9';
+ m_state.context.gpr.__r10 = ('r' << 8) + 'a';
+ m_state.context.gpr.__r11 = ('r' << 8) + 'b';
+ m_state.context.gpr.__r12 = ('r' << 8) + 'c';
+ m_state.context.gpr.__r13 = ('r' << 8) + 'd';
+ m_state.context.gpr.__r14 = ('r' << 8) + 'e';
+ m_state.context.gpr.__r15 = ('r' << 8) + 'f';
+ m_state.context.gpr.__rip = ('i' << 8) + 'p';
+ m_state.context.gpr.__rflags = ('f' << 8) + 'l';
+ m_state.context.gpr.__cs = ('c' << 8) + 's';
+ m_state.context.gpr.__fs = ('f' << 8) + 's';
+ m_state.context.gpr.__gs = ('g' << 8) + 's';
+ m_state.SetError(e_regSetGPR, Read, 0);
+#else
+ mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
+ m_state.SetError(e_regSetGPR, Read, ::thread_get_state(m_thread->ThreadID(), x86_THREAD_STATE64, (thread_state_t)&m_state.context.gpr, &count));
+ DNBLogThreadedIf (LOG_THREAD, "::thread_get_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x"
+ "\n\trax = %16.16llx rbx = %16.16llx rcx = %16.16llx rdx = %16.16llx"
+ "\n\trdi = %16.16llx rsi = %16.16llx rbp = %16.16llx rsp = %16.16llx"
+ "\n\t r8 = %16.16llx r9 = %16.16llx r10 = %16.16llx r11 = %16.16llx"
+ "\n\tr12 = %16.16llx r13 = %16.16llx r14 = %16.16llx r15 = %16.16llx"
+ "\n\trip = %16.16llx"
+ "\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx",
+ m_thread->ThreadID(), x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT,
+ m_state.GetError(e_regSetGPR, Read),
+ m_state.context.gpr.__rax,m_state.context.gpr.__rbx,m_state.context.gpr.__rcx,
+ m_state.context.gpr.__rdx,m_state.context.gpr.__rdi,m_state.context.gpr.__rsi,
+ m_state.context.gpr.__rbp,m_state.context.gpr.__rsp,m_state.context.gpr.__r8,
+ m_state.context.gpr.__r9, m_state.context.gpr.__r10,m_state.context.gpr.__r11,
+ m_state.context.gpr.__r12,m_state.context.gpr.__r13,m_state.context.gpr.__r14,
+ m_state.context.gpr.__r15,m_state.context.gpr.__rip,m_state.context.gpr.__rflags,
+ m_state.context.gpr.__cs,m_state.context.gpr.__fs, m_state.context.gpr.__gs);
+
+ // DNBLogThreadedIf (LOG_THREAD, "thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x"
+ // "\n\trax = %16.16llx"
+ // "\n\trbx = %16.16llx"
+ // "\n\trcx = %16.16llx"
+ // "\n\trdx = %16.16llx"
+ // "\n\trdi = %16.16llx"
+ // "\n\trsi = %16.16llx"
+ // "\n\trbp = %16.16llx"
+ // "\n\trsp = %16.16llx"
+ // "\n\t r8 = %16.16llx"
+ // "\n\t r9 = %16.16llx"
+ // "\n\tr10 = %16.16llx"
+ // "\n\tr11 = %16.16llx"
+ // "\n\tr12 = %16.16llx"
+ // "\n\tr13 = %16.16llx"
+ // "\n\tr14 = %16.16llx"
+ // "\n\tr15 = %16.16llx"
+ // "\n\trip = %16.16llx"
+ // "\n\tflg = %16.16llx"
+ // "\n\t cs = %16.16llx"
+ // "\n\t fs = %16.16llx"
+ // "\n\t gs = %16.16llx",
+ // m_thread->ThreadID(),
+ // x86_THREAD_STATE64,
+ // x86_THREAD_STATE64_COUNT,
+ // m_state.GetError(e_regSetGPR, Read),
+ // m_state.context.gpr.__rax,
+ // m_state.context.gpr.__rbx,
+ // m_state.context.gpr.__rcx,
+ // m_state.context.gpr.__rdx,
+ // m_state.context.gpr.__rdi,
+ // m_state.context.gpr.__rsi,
+ // m_state.context.gpr.__rbp,
+ // m_state.context.gpr.__rsp,
+ // m_state.context.gpr.__r8,
+ // m_state.context.gpr.__r9,
+ // m_state.context.gpr.__r10,
+ // m_state.context.gpr.__r11,
+ // m_state.context.gpr.__r12,
+ // m_state.context.gpr.__r13,
+ // m_state.context.gpr.__r14,
+ // m_state.context.gpr.__r15,
+ // m_state.context.gpr.__rip,
+ // m_state.context.gpr.__rflags,
+ // m_state.context.gpr.__cs,
+ // m_state.context.gpr.__fs,
+ // m_state.context.gpr.__gs);
+#endif
+ }
+ return m_state.GetError(e_regSetGPR, Read);
+}
+
+// Uncomment the value below to verify the values in the debugger.
+//#define DEBUG_FPU_VALUES 1 // DO NOT CHECK IN WITH THIS DEFINE ENABLED
+
+kern_return_t
+DNBArchImplX86_64::GetFPUState(bool force)
+{
+ if (force || m_state.GetError(e_regSetFPU, Read))
+ {
+#if DEBUG_FPU_VALUES
+ m_state.context.fpu.__fpu_reserved[0] = -1;
+ m_state.context.fpu.__fpu_reserved[1] = -1;
+ *(uint16_t *)&(m_state.context.fpu.__fpu_fcw) = 0x1234;
+ *(uint16_t *)&(m_state.context.fpu.__fpu_fsw) = 0x5678;
+ m_state.context.fpu.__fpu_ftw = 1;
+ m_state.context.fpu.__fpu_rsrv1 = UINT8_MAX;
+ m_state.context.fpu.__fpu_fop = 2;
+ m_state.context.fpu.__fpu_ip = 3;
+ m_state.context.fpu.__fpu_cs = 4;
+ m_state.context.fpu.__fpu_rsrv2 = 5;
+ m_state.context.fpu.__fpu_dp = 6;
+ m_state.context.fpu.__fpu_ds = 7;
+ m_state.context.fpu.__fpu_rsrv3 = UINT16_MAX;
+ m_state.context.fpu.__fpu_mxcsr = 8;
+ m_state.context.fpu.__fpu_mxcsrmask = 9;
+ int i;
+ for (i=0; i<16; ++i)
+ {
+ if (i<10)
+ {
+ m_state.context.fpu.__fpu_stmm0.__mmst_reg[i] = 'a';
+ m_state.context.fpu.__fpu_stmm1.__mmst_reg[i] = 'b';
+ m_state.context.fpu.__fpu_stmm2.__mmst_reg[i] = 'c';
+ m_state.context.fpu.__fpu_stmm3.__mmst_reg[i] = 'd';
+ m_state.context.fpu.__fpu_stmm4.__mmst_reg[i] = 'e';
+ m_state.context.fpu.__fpu_stmm5.__mmst_reg[i] = 'f';
+ m_state.context.fpu.__fpu_stmm6.__mmst_reg[i] = 'g';
+ m_state.context.fpu.__fpu_stmm7.__mmst_reg[i] = 'h';
+ }
+ else
+ {
+ m_state.context.fpu.__fpu_stmm0.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm1.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm2.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm3.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm4.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm5.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm6.__mmst_reg[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_stmm7.__mmst_reg[i] = INT8_MIN;
+ }
+
+ m_state.context.fpu.__fpu_xmm0.__xmm_reg[i] = '0';
+ m_state.context.fpu.__fpu_xmm1.__xmm_reg[i] = '1';
+ m_state.context.fpu.__fpu_xmm2.__xmm_reg[i] = '2';
+ m_state.context.fpu.__fpu_xmm3.__xmm_reg[i] = '3';
+ m_state.context.fpu.__fpu_xmm4.__xmm_reg[i] = '4';
+ m_state.context.fpu.__fpu_xmm5.__xmm_reg[i] = '5';
+ m_state.context.fpu.__fpu_xmm6.__xmm_reg[i] = '6';
+ m_state.context.fpu.__fpu_xmm7.__xmm_reg[i] = '7';
+ m_state.context.fpu.__fpu_xmm8.__xmm_reg[i] = '8';
+ m_state.context.fpu.__fpu_xmm9.__xmm_reg[i] = '9';
+ m_state.context.fpu.__fpu_xmm10.__xmm_reg[i] = 'A';
+ m_state.context.fpu.__fpu_xmm11.__xmm_reg[i] = 'B';
+ m_state.context.fpu.__fpu_xmm12.__xmm_reg[i] = 'C';
+ m_state.context.fpu.__fpu_xmm13.__xmm_reg[i] = 'D';
+ m_state.context.fpu.__fpu_xmm14.__xmm_reg[i] = 'E';
+ m_state.context.fpu.__fpu_xmm15.__xmm_reg[i] = 'F';
+ }
+ for (i=0; i<sizeof(m_state.context.fpu.__fpu_rsrv4); ++i)
+ m_state.context.fpu.__fpu_rsrv4[i] = INT8_MIN;
+ m_state.context.fpu.__fpu_reserved1 = -1;
+ m_state.SetError(e_regSetFPU, Read, 0);
+#else
+ mach_msg_type_number_t count = x86_FLOAT_STATE64_COUNT;
+ m_state.SetError(e_regSetFPU, Read, ::thread_get_state(m_thread->ThreadID(), x86_FLOAT_STATE64, (thread_state_t)&m_state.context.fpu, &count));
+#endif
+ }
+ return m_state.GetError(e_regSetFPU, Read);
+}
+
+kern_return_t
+DNBArchImplX86_64::GetEXCState(bool force)
+{
+ if (force || m_state.GetError(e_regSetEXC, Read))
+ {
+ mach_msg_type_number_t count = X86_EXCEPTION_STATE64_COUNT;
+ m_state.SetError(e_regSetEXC, Read, ::thread_get_state(m_thread->ThreadID(), x86_EXCEPTION_STATE64, (thread_state_t)&m_state.context.exc, &count));
+ }
+ return m_state.GetError(e_regSetEXC, Read);
+}
+
+kern_return_t
+DNBArchImplX86_64::SetGPRState()
+{
+ m_state.SetError(e_regSetGPR, Write, ::thread_set_state(m_thread->ThreadID(), x86_THREAD_STATE64, (thread_state_t)&m_state.context.gpr, x86_THREAD_STATE64_COUNT));
+ DNBLogThreadedIf (LOG_THREAD, "::thread_set_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x"
+ "\n\trax = %16.16llx rbx = %16.16llx rcx = %16.16llx rdx = %16.16llx"
+ "\n\trdi = %16.16llx rsi = %16.16llx rbp = %16.16llx rsp = %16.16llx"
+ "\n\t r8 = %16.16llx r9 = %16.16llx r10 = %16.16llx r11 = %16.16llx"
+ "\n\tr12 = %16.16llx r13 = %16.16llx r14 = %16.16llx r15 = %16.16llx"
+ "\n\trip = %16.16llx"
+ "\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx",
+ m_thread->ThreadID(), x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT,
+ m_state.GetError(e_regSetGPR, Write),
+ m_state.context.gpr.__rax,m_state.context.gpr.__rbx,m_state.context.gpr.__rcx,
+ m_state.context.gpr.__rdx,m_state.context.gpr.__rdi,m_state.context.gpr.__rsi,
+ m_state.context.gpr.__rbp,m_state.context.gpr.__rsp,m_state.context.gpr.__r8,
+ m_state.context.gpr.__r9, m_state.context.gpr.__r10,m_state.context.gpr.__r11,
+ m_state.context.gpr.__r12,m_state.context.gpr.__r13,m_state.context.gpr.__r14,
+ m_state.context.gpr.__r15,m_state.context.gpr.__rip,m_state.context.gpr.__rflags,
+ m_state.context.gpr.__cs, m_state.context.gpr.__fs, m_state.context.gpr.__gs);
+ return m_state.GetError(e_regSetGPR, Write);
+}
+
+kern_return_t
+DNBArchImplX86_64::SetFPUState()
+{
+ m_state.SetError(e_regSetFPU, Write, ::thread_set_state(m_thread->ThreadID(), x86_FLOAT_STATE64, (thread_state_t)&m_state.context.fpu, x86_FLOAT_STATE64_COUNT));
+ return m_state.GetError(e_regSetFPU, Write);
+}
+
+kern_return_t
+DNBArchImplX86_64::SetEXCState()
+{
+ m_state.SetError(e_regSetEXC, Write, ::thread_set_state(m_thread->ThreadID(), x86_EXCEPTION_STATE64, (thread_state_t)&m_state.context.exc, X86_EXCEPTION_STATE64_COUNT));
+ return m_state.GetError(e_regSetEXC, Write);
+}
+
+void
+DNBArchImplX86_64::ThreadWillResume()
+{
+ // Do we need to step this thread? If so, let the mach thread tell us so.
+ if (m_thread->IsStepping())
+ {
+ // This is the primary thread, let the arch do anything it needs
+ EnableHardwareSingleStep(true) == KERN_SUCCESS;
+ }
+}
+
+bool
+DNBArchImplX86_64::ThreadDidStop()
+{
+ bool success = true;
+
+ m_state.InvalidateAllRegisterStates();
+
+ // Are we stepping a single instruction?
+ if (GetGPRState(true) == KERN_SUCCESS)
+ {
+ // We are single stepping, was this the primary thread?
+ if (m_thread->IsStepping())
+ {
+ // This was the primary thread, we need to clear the trace
+ // bit if so.
+ success = EnableHardwareSingleStep(false) == KERN_SUCCESS;
+ }
+ else
+ {
+ // The MachThread will automatically restore the suspend count
+ // in ThreadDidStop(), so we don't need to do anything here if
+ // we weren't the primary thread the last time
+ }
+ }
+ return success;
+}
+
+bool
+DNBArchImplX86_64::NotifyException(MachException::Data& exc)
+{
+ switch (exc.exc_type)
+ {
+ case EXC_BAD_ACCESS:
+ break;
+ case EXC_BAD_INSTRUCTION:
+ break;
+ case EXC_ARITHMETIC:
+ break;
+ case EXC_EMULATION:
+ break;
+ case EXC_SOFTWARE:
+ break;
+ case EXC_BREAKPOINT:
+ if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2)
+ {
+ nub_addr_t pc = GetPC(INVALID_NUB_ADDRESS);
+ if (pc != INVALID_NUB_ADDRESS && pc > 0)
+ {
+ pc -= 1;
+ // Check for a breakpoint at one byte prior to the current PC value
+ // since the PC will be just past the trap.
+
+ nub_break_t breakID = m_thread->Process()->Breakpoints().FindIDByAddress(pc);
+ if (NUB_BREAK_ID_IS_VALID(breakID))
+ {
+ // Backup the PC for i386 since the trap was taken and the PC
+ // is at the address following the single byte trap instruction.
+ if (m_state.context.gpr.__rip > 0)
+ {
+ m_state.context.gpr.__rip = pc;
+ // Write the new PC back out
+ SetGPRState ();
+ }
+
+ m_thread->SetCurrentBreakpoint(breakID);
+ }
+ return true;
+ }
+ }
+ break;
+ case EXC_SYSCALL:
+ break;
+ case EXC_MACH_SYSCALL:
+ break;
+ case EXC_RPC_ALERT:
+ break;
+ }
+ return false;
+}
+
+
+// Set the single step bit in the processor status register.
+kern_return_t
+DNBArchImplX86_64::EnableHardwareSingleStep (bool enable)
+{
+ if (GetGPRState(false) == KERN_SUCCESS)
+ {
+ const uint32_t trace_bit = 0x100u;
+ if (enable)
+ m_state.context.gpr.__rflags |= trace_bit;
+ else
+ m_state.context.gpr.__rflags &= ~trace_bit;
+ return SetGPRState();
+ }
+ return m_state.GetError(e_regSetGPR, Read);
+}
+
+
+//----------------------------------------------------------------------
+// Register information defintions
+//----------------------------------------------------------------------
+
+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,
+ k_num_gpr_regs
+};
+
+enum {
+ 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,
+ k_num_fpu_regs,
+
+ // 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 {
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+ k_num_exc_regs,
+};
+
+
+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,
+
+};
+
+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,
+};
+
+#define GPR_OFFSET(reg) (offsetof (DNBArchImplX86_64::GPR, __##reg))
+#define FPU_OFFSET(reg) (offsetof (DNBArchImplX86_64::FPU, __fpu_##reg) + offsetof (DNBArchImplX86_64::Context, fpu))
+#define EXC_OFFSET(reg) (offsetof (DNBArchImplX86_64::EXC, __##reg) + offsetof (DNBArchImplX86_64::Context, exc))
+
+#define GPR_SIZE(reg) (sizeof(((DNBArchImplX86_64::GPR *)NULL)->__##reg))
+#define FPU_SIZE_UINT(reg) (sizeof(((DNBArchImplX86_64::FPU *)NULL)->__fpu_##reg))
+#define FPU_SIZE_MMST(reg) (sizeof(((DNBArchImplX86_64::FPU *)NULL)->__fpu_##reg.__mmst_reg))
+#define FPU_SIZE_XMM(reg) (sizeof(((DNBArchImplX86_64::FPU *)NULL)->__fpu_##reg.__xmm_reg))
+#define EXC_SIZE(reg) (sizeof(((DNBArchImplX86_64::EXC *)NULL)->__##reg))
+
+// 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) { e_regSetGPR, gpr_##reg, #reg, NULL, Uint, Hex, GPR_SIZE(reg), GPR_OFFSET(reg), gcc_dwarf_##reg, gcc_dwarf_##reg, INVALID_NUB_REGNUM, gdb_##reg }
+#define DEFINE_GPR_ALT(reg, alt, gen) { e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, GPR_SIZE(reg), GPR_OFFSET(reg), gcc_dwarf_##reg, gcc_dwarf_##reg, gen, gdb_##reg }
+#define DEFINE_GPR_ALT2(reg, alt) { e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, GPR_SIZE(reg), GPR_OFFSET(reg), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, gdb_##reg }
+
+// General purpose registers for 64 bit
+const DNBRegisterInfo
+DNBArchImplX86_64::g_gpr_registers[] =
+{
+ DEFINE_GPR (rax),
+ DEFINE_GPR (rbx),
+ DEFINE_GPR (rcx),
+ DEFINE_GPR (rdx),
+ DEFINE_GPR (rdi),
+ DEFINE_GPR (rsi),
+ DEFINE_GPR_ALT (rbp, "fp", GENERIC_REGNUM_FP),
+ DEFINE_GPR_ALT (rsp, "sp", GENERIC_REGNUM_SP),
+ DEFINE_GPR (r8),
+ DEFINE_GPR (r9),
+ DEFINE_GPR (r10),
+ DEFINE_GPR (r11),
+ DEFINE_GPR (r12),
+ DEFINE_GPR (r13),
+ DEFINE_GPR (r14),
+ DEFINE_GPR (r15),
+ DEFINE_GPR_ALT (rip, "pc", GENERIC_REGNUM_PC),
+ DEFINE_GPR_ALT2 (rflags, "flags"),
+ DEFINE_GPR_ALT2 (cs, NULL),
+ DEFINE_GPR_ALT2 (fs, NULL),
+ DEFINE_GPR_ALT2 (gs, NULL),
+};
+
+// Floating point registers 64 bit
+const DNBRegisterInfo
+DNBArchImplX86_64::g_fpu_registers[] =
+{
+ { e_regSetFPU, fpu_fcw , "fctrl" , NULL, Uint, Hex, FPU_SIZE_UINT(fcw) , FPU_OFFSET(fcw) , -1, -1, -1, -1 },
+ { e_regSetFPU, fpu_fsw , "fstat" , NULL, Uint, Hex, FPU_SIZE_UINT(fsw) , FPU_OFFSET(fsw) , -1, -1, -1, -1 },
+ { e_regSetFPU, fpu_ftw , "ftag" , NULL, Uint, Hex, FPU_SIZE_UINT(ftw) , FPU_OFFSET(ftw) , -1, -1, -1, -1 },
+ { e_regSetFPU, fpu_fop , "fop" , NULL, Uint, Hex, FPU_SIZE_UINT(fop) , FPU_OFFSET(fop) , -1, -1, -1, -1 },
+ { e_regSetFPU, fpu_ip , "fioff" , NULL, Uint, Hex, FPU_SIZE_UINT(ip) , FPU_OFFSET(ip) , -1, -1, -1, -1 },
+ { e_regSetFPU, fpu_cs , "fiseg" , NULL, Uint, Hex, FPU_SIZE_UINT(cs) , FPU_OFFSET(cs) , -1, -1, -1, -1 },
+ { e_regSetFPU, fpu_dp , "fooff" , NULL, Uint, Hex, FPU_SIZE_UINT(dp) , FPU_OFFSET(dp) , -1, -1, -1, -1 },
+ { e_regSetFPU, fpu_ds , "foseg" , NULL, Uint, Hex, FPU_SIZE_UINT(ds) , FPU_OFFSET(ds) , -1, -1, -1, -1 },
+ { e_regSetFPU, fpu_mxcsr , "mxcsr" , NULL, Uint, Hex, FPU_SIZE_UINT(mxcsr) , FPU_OFFSET(mxcsr) , -1, -1, -1, -1 },
+ { e_regSetFPU, fpu_mxcsrmask, "mxcsrmask" , NULL, Uint, Hex, FPU_SIZE_UINT(mxcsrmask) , FPU_OFFSET(mxcsrmask) , -1, -1, -1, -1 },
+
+ { e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm0), FPU_OFFSET(stmm0), gcc_dwarf_stmm0, gcc_dwarf_stmm0, -1, gdb_stmm0 },
+ { e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm1), FPU_OFFSET(stmm1), gcc_dwarf_stmm1, gcc_dwarf_stmm1, -1, gdb_stmm1 },
+ { e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm2), FPU_OFFSET(stmm2), gcc_dwarf_stmm2, gcc_dwarf_stmm2, -1, gdb_stmm2 },
+ { e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm3), FPU_OFFSET(stmm3), gcc_dwarf_stmm3, gcc_dwarf_stmm3, -1, gdb_stmm3 },
+ { e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm4), FPU_OFFSET(stmm4), gcc_dwarf_stmm4, gcc_dwarf_stmm4, -1, gdb_stmm4 },
+ { e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm5), FPU_OFFSET(stmm5), gcc_dwarf_stmm5, gcc_dwarf_stmm5, -1, gdb_stmm5 },
+ { e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm6), FPU_OFFSET(stmm6), gcc_dwarf_stmm6, gcc_dwarf_stmm6, -1, gdb_stmm6 },
+ { e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm7), FPU_OFFSET(stmm7), gcc_dwarf_stmm7, gcc_dwarf_stmm7, -1, gdb_stmm7 },
+
+ { e_regSetFPU, fpu_xmm0 , "xmm0" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm0) , FPU_OFFSET(xmm0) , gcc_dwarf_xmm0 , gcc_dwarf_xmm0 , -1, gdb_xmm0 },
+ { e_regSetFPU, fpu_xmm1 , "xmm1" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm1) , FPU_OFFSET(xmm1) , gcc_dwarf_xmm1 , gcc_dwarf_xmm1 , -1, gdb_xmm1 },
+ { e_regSetFPU, fpu_xmm2 , "xmm2" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm2) , FPU_OFFSET(xmm2) , gcc_dwarf_xmm2 , gcc_dwarf_xmm2 , -1, gdb_xmm2 },
+ { e_regSetFPU, fpu_xmm3 , "xmm3" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm3) , FPU_OFFSET(xmm3) , gcc_dwarf_xmm3 , gcc_dwarf_xmm3 , -1, gdb_xmm3 },
+ { e_regSetFPU, fpu_xmm4 , "xmm4" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm4) , FPU_OFFSET(xmm4) , gcc_dwarf_xmm4 , gcc_dwarf_xmm4 , -1, gdb_xmm4 },
+ { e_regSetFPU, fpu_xmm5 , "xmm5" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm5) , FPU_OFFSET(xmm5) , gcc_dwarf_xmm5 , gcc_dwarf_xmm5 , -1, gdb_xmm5 },
+ { e_regSetFPU, fpu_xmm6 , "xmm6" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm6) , FPU_OFFSET(xmm6) , gcc_dwarf_xmm6 , gcc_dwarf_xmm6 , -1, gdb_xmm6 },
+ { e_regSetFPU, fpu_xmm7 , "xmm7" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm7) , FPU_OFFSET(xmm7) , gcc_dwarf_xmm7 , gcc_dwarf_xmm7 , -1, gdb_xmm7 },
+ { e_regSetFPU, fpu_xmm8 , "xmm8" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm8) , FPU_OFFSET(xmm8) , gcc_dwarf_xmm8 , gcc_dwarf_xmm8 , -1, gdb_xmm8 },
+ { e_regSetFPU, fpu_xmm9 , "xmm9" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm9) , FPU_OFFSET(xmm9) , gcc_dwarf_xmm9 , gcc_dwarf_xmm9 , -1, gdb_xmm9 },
+ { e_regSetFPU, fpu_xmm10, "xmm10" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm10) , FPU_OFFSET(xmm10), gcc_dwarf_xmm10, gcc_dwarf_xmm10, -1, gdb_xmm10 },
+ { e_regSetFPU, fpu_xmm11, "xmm11" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm11) , FPU_OFFSET(xmm11), gcc_dwarf_xmm11, gcc_dwarf_xmm11, -1, gdb_xmm11 },
+ { e_regSetFPU, fpu_xmm12, "xmm12" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm12) , FPU_OFFSET(xmm12), gcc_dwarf_xmm12, gcc_dwarf_xmm12, -1, gdb_xmm12 },
+ { e_regSetFPU, fpu_xmm13, "xmm13" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm13) , FPU_OFFSET(xmm13), gcc_dwarf_xmm13, gcc_dwarf_xmm13, -1, gdb_xmm13 },
+ { e_regSetFPU, fpu_xmm14, "xmm14" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm14) , FPU_OFFSET(xmm14), gcc_dwarf_xmm14, gcc_dwarf_xmm14, -1, gdb_xmm14 },
+ { e_regSetFPU, fpu_xmm15, "xmm15" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm15) , FPU_OFFSET(xmm15), gcc_dwarf_xmm15, gcc_dwarf_xmm15, -1, gdb_xmm15 },
+};
+
+// Exception registers
+
+const DNBRegisterInfo
+DNBArchImplX86_64::g_exc_registers[] =
+{
+ { e_regSetEXC, exc_trapno, "trapno" , NULL, Uint, Hex, EXC_SIZE (trapno) , EXC_OFFSET (trapno) , -1, -1, -1, -1 },
+ { e_regSetEXC, exc_err, "err" , NULL, Uint, Hex, EXC_SIZE (err) , EXC_OFFSET (err) , -1, -1, -1, -1 },
+ { e_regSetEXC, exc_faultvaddr, "faultvaddr", NULL, Uint, Hex, EXC_SIZE (faultvaddr), EXC_OFFSET (faultvaddr) , -1, -1, -1, -1 }
+};
+
+// Number of registers in each register set
+const size_t DNBArchImplX86_64::k_num_gpr_registers = sizeof(g_gpr_registers)/sizeof(DNBRegisterInfo);
+const size_t DNBArchImplX86_64::k_num_fpu_registers = sizeof(g_fpu_registers)/sizeof(DNBRegisterInfo);
+const size_t DNBArchImplX86_64::k_num_exc_registers = sizeof(g_exc_registers)/sizeof(DNBRegisterInfo);
+const size_t DNBArchImplX86_64::k_num_all_registers = k_num_gpr_registers + k_num_fpu_registers + k_num_exc_registers;
+
+//----------------------------------------------------------------------
+// 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.
+//----------------------------------------------------------------------
+const DNBRegisterSetInfo
+DNBArchImplX86_64::g_reg_sets[] =
+{
+ { "x86_64 Registers", NULL, k_num_all_registers },
+ { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers },
+ { "Floating Point Registers", g_fpu_registers, k_num_fpu_registers },
+ { "Exception State Registers", g_exc_registers, k_num_exc_registers }
+};
+// Total number of register sets for this architecture
+const size_t DNBArchImplX86_64::k_num_register_sets = sizeof(g_reg_sets)/sizeof(DNBRegisterSetInfo);
+
+
+const DNBRegisterSetInfo *
+DNBArchImplX86_64::GetRegisterSetInfo (nub_size_t *num_reg_sets)
+{
+ *num_reg_sets = k_num_register_sets;
+ return g_reg_sets;
+}
+
+bool
+DNBArchImplX86_64::GetRegisterValue(int set, int reg, DNBRegisterValue *value)
+{
+ if (set == REGISTER_SET_GENERIC)
+ {
+ switch (reg)
+ {
+ case GENERIC_REGNUM_PC: // Program Counter
+ set = e_regSetGPR;
+ reg = gpr_rip;
+ break;
+
+ case GENERIC_REGNUM_SP: // Stack Pointer
+ set = e_regSetGPR;
+ reg = gpr_rsp;
+ break;
+
+ case GENERIC_REGNUM_FP: // Frame Pointer
+ set = e_regSetGPR;
+ reg = gpr_rbp;
+ break;
+
+ case GENERIC_REGNUM_FLAGS: // Processor flags register
+ set = e_regSetGPR;
+ reg = gpr_rflags;
+ break;
+
+ case GENERIC_REGNUM_RA: // Return Address
+ default:
+ return false;
+ }
+ }
+
+ if (GetRegisterState(set, false) != KERN_SUCCESS)
+ return false;
+
+ const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg);
+ if (regInfo)
+ {
+ value->info = *regInfo;
+ switch (set)
+ {
+ case e_regSetGPR:
+ if (reg < k_num_gpr_registers)
+ {
+ value->value.uint64 = ((uint64_t*)(&m_state.context.gpr))[reg];
+ return true;
+ }
+ break;
+
+ case e_regSetFPU:
+ switch (reg)
+ {
+ case fpu_fcw: value->value.uint16 = *((uint16_t *)(&m_state.context.fpu.__fpu_fcw)); return true;
+ case fpu_fsw: value->value.uint16 = *((uint16_t *)(&m_state.context.fpu.__fpu_fsw)); return true;
+ case fpu_ftw: value->value.uint8 = m_state.context.fpu.__fpu_ftw; return true;
+ case fpu_fop: value->value.uint16 = m_state.context.fpu.__fpu_fop; return true;
+ case fpu_ip: value->value.uint32 = m_state.context.fpu.__fpu_ip; return true;
+ case fpu_cs: value->value.uint16 = m_state.context.fpu.__fpu_cs; return true;
+ case fpu_dp: value->value.uint32 = m_state.context.fpu.__fpu_dp; return true;
+ case fpu_ds: value->value.uint16 = m_state.context.fpu.__fpu_ds; return true;
+ case fpu_mxcsr: value->value.uint32 = m_state.context.fpu.__fpu_mxcsr; return true;
+ case fpu_mxcsrmask: value->value.uint32 = m_state.context.fpu.__fpu_mxcsrmask; return true;
+
+ 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(&value->value.uint8, &m_state.context.fpu.__fpu_stmm0 + (reg - fpu_stmm0), 10);
+ return true;
+
+ 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(&value->value.uint8, &m_state.context.fpu.__fpu_xmm0 + (reg - fpu_xmm0), 16);
+ return true;
+ }
+ break;
+
+ case e_regSetEXC:
+ switch (reg)
+ {
+ case exc_trapno: value->value.uint32 = m_state.context.exc.__trapno; return true;
+ case exc_err: value->value.uint32 = m_state.context.exc.__err; return true;
+ case exc_faultvaddr:value->value.uint64 = m_state.context.exc.__faultvaddr; return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+
+bool
+DNBArchImplX86_64::SetRegisterValue(int set, int reg, const DNBRegisterValue *value)
+{
+ if (set == REGISTER_SET_GENERIC)
+ {
+ switch (reg)
+ {
+ case GENERIC_REGNUM_PC: // Program Counter
+ set = e_regSetGPR;
+ reg = gpr_rip;
+ break;
+
+ case GENERIC_REGNUM_SP: // Stack Pointer
+ set = e_regSetGPR;
+ reg = gpr_rsp;
+ break;
+
+ case GENERIC_REGNUM_FP: // Frame Pointer
+ set = e_regSetGPR;
+ reg = gpr_rbp;
+ break;
+
+ case GENERIC_REGNUM_FLAGS: // Processor flags register
+ set = e_regSetGPR;
+ reg = gpr_rflags;
+ break;
+
+ case GENERIC_REGNUM_RA: // Return Address
+ default:
+ return false;
+ }
+ }
+
+ if (GetRegisterState(set, false) != KERN_SUCCESS)
+ return false;
+
+ bool success = false;
+ const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg);
+ if (regInfo)
+ {
+ switch (set)
+ {
+ case e_regSetGPR:
+ if (reg < k_num_gpr_registers)
+ {
+ ((uint64_t*)(&m_state.context.gpr))[reg] = value->value.uint64;
+ success = true;
+ }
+ break;
+
+ case e_regSetFPU:
+ switch (reg)
+ {
+ case fpu_fcw: *((uint16_t *)(&m_state.context.fpu.__fpu_fcw)) = value->value.uint16; success = true; break;
+ case fpu_fsw: *((uint16_t *)(&m_state.context.fpu.__fpu_fsw)) = value->value.uint16; success = true; break;
+ case fpu_ftw: m_state.context.fpu.__fpu_ftw = value->value.uint8; success = true; break;
+ case fpu_fop: m_state.context.fpu.__fpu_fop = value->value.uint16; success = true; break;
+ case fpu_ip: m_state.context.fpu.__fpu_ip = value->value.uint32; success = true; break;
+ case fpu_cs: m_state.context.fpu.__fpu_cs = value->value.uint16; success = true; break;
+ case fpu_dp: m_state.context.fpu.__fpu_dp = value->value.uint32; success = true; break;
+ case fpu_ds: m_state.context.fpu.__fpu_ds = value->value.uint16; success = true; break;
+ case fpu_mxcsr: m_state.context.fpu.__fpu_mxcsr = value->value.uint32; success = true; break;
+ case fpu_mxcsrmask: m_state.context.fpu.__fpu_mxcsrmask = value->value.uint32; success = true; 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 (&m_state.context.fpu.__fpu_stmm0 + (reg - fpu_stmm0), &value->value.uint8, 10);
+ success = true;
+ 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 (&m_state.context.fpu.__fpu_xmm0 + (reg - fpu_xmm0), &value->value.uint8, 16);
+ success = true;
+ break;
+ }
+ break;
+
+ case e_regSetEXC:
+ switch (reg)
+ {
+ case exc_trapno: m_state.context.exc.__trapno = value->value.uint32; success = true; break;
+ case exc_err: m_state.context.exc.__err = value->value.uint32; success = true; break;
+ case exc_faultvaddr:m_state.context.exc.__faultvaddr = value->value.uint64; success = true; break;
+ }
+ break;
+ }
+ }
+
+ if (success)
+ return SetRegisterState(set) == KERN_SUCCESS;
+ return false;
+}
+
+
+nub_size_t
+DNBArchImplX86_64::GetRegisterContext (void *buf, nub_size_t buf_len)
+{
+ nub_size_t size = sizeof (m_state.context);
+
+ if (buf && buf_len)
+ {
+ if (size > buf_len)
+ size = buf_len;
+
+ bool force = false;
+ if (GetGPRState(force) | GetFPUState(force) | GetEXCState(force))
+ return 0;
+ ::memcpy (buf, &m_state.context, size);
+ }
+ DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::GetRegisterContext (buf = %p, len = %zu) => %zu", buf, buf_len, size);
+ // Return the size of the register context even if NULL was passed in
+ return size;
+}
+
+nub_size_t
+DNBArchImplX86_64::SetRegisterContext (const void *buf, nub_size_t buf_len)
+{
+ nub_size_t size = sizeof (m_state.context);
+ if (buf == NULL || buf_len == 0)
+ size = 0;
+
+ if (size)
+ {
+ if (size > buf_len)
+ size = buf_len;
+
+ ::memcpy (&m_state.context, buf, size);
+ SetGPRState();
+ SetFPUState();
+ SetEXCState();
+ }
+ DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::SetRegisterContext (buf = %p, len = %zu) => %zu", buf, buf_len, size);
+ return size;
+}
+
+
+kern_return_t
+DNBArchImplX86_64::GetRegisterState(int set, bool force)
+{
+ switch (set)
+ {
+ case e_regSetALL: return GetGPRState(force) | GetFPUState(force) | GetEXCState(force);
+ case e_regSetGPR: return GetGPRState(force);
+ case e_regSetFPU: return GetFPUState(force);
+ case e_regSetEXC: return GetEXCState(force);
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+kern_return_t
+DNBArchImplX86_64::SetRegisterState(int set)
+{
+ // Make sure we have a valid context to set.
+ if (RegisterSetStateIsValid(set))
+ {
+ switch (set)
+ {
+ case e_regSetALL: return SetGPRState() | SetFPUState() | SetEXCState();
+ case e_regSetGPR: return SetGPRState();
+ case e_regSetFPU: return SetFPUState();
+ case e_regSetEXC: return SetEXCState();
+ default: break;
+ }
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+bool
+DNBArchImplX86_64::RegisterSetStateIsValid (int set) const
+{
+ return m_state.RegsAreValid(set);
+}
+
+
+
+#endif // #if defined (__i386__)
diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h
new file mode 100644
index 00000000000..f445d473892
--- /dev/null
+++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h
@@ -0,0 +1,199 @@
+//===-- DNBArchImplX86_64.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/25/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DNBArchImplX86_64_h__
+#define __DNBArchImplX86_64_h__
+
+//#if defined (__i386__)
+#if defined(__x86_64__)
+#include "DNBArch.h"
+#include <mach/mach_types.h>
+#include <mach/thread_status.h>
+
+
+class MachThread;
+
+class DNBArchImplX86_64 : public DNBArchProtocol
+{
+public:
+ DNBArchImplX86_64(MachThread *thread) :
+ m_thread(thread),
+ m_state()
+ {
+ }
+ virtual ~DNBArchImplX86_64()
+ {
+ }
+
+ static const DNBRegisterSetInfo *
+ GetRegisterSetInfo(nub_size_t *num_reg_sets);
+
+ virtual bool GetRegisterValue(int set, int reg, DNBRegisterValue *reg);
+ virtual bool SetRegisterValue(int set, int reg, const DNBRegisterValue *reg);
+ virtual nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len);
+ virtual nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len);
+
+ virtual kern_return_t GetRegisterState (int set, bool force);
+ virtual kern_return_t SetRegisterState (int set);
+ virtual bool RegisterSetStateIsValid (int set) const;
+
+ virtual uint64_t GetPC(uint64_t failValue); // Get program counter
+ virtual kern_return_t SetPC(uint64_t value);
+ virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer
+ virtual void ThreadWillResume();
+ virtual bool ThreadDidStop();
+ virtual bool NotifyException(MachException::Data& exc);
+
+ static const uint8_t * const SoftwareBreakpointOpcode (nub_size_t byte_size);
+ static uint32_t GetCPUType();
+
+protected:
+ kern_return_t EnableHardwareSingleStep (bool enable);
+
+ typedef x86_thread_state64_t GPR;
+ typedef x86_float_state64_t FPU;
+ typedef x86_exception_state64_t EXC;
+
+ static const DNBRegisterInfo g_gpr_registers[];
+ static const DNBRegisterInfo g_fpu_registers[];
+ static const DNBRegisterInfo g_exc_registers[];
+ static const DNBRegisterSetInfo g_reg_sets[];
+ static const size_t k_num_gpr_registers;
+ static const size_t k_num_fpu_registers;
+ static const size_t k_num_exc_registers;
+ static const size_t k_num_all_registers;
+ static const size_t k_num_register_sets;
+
+ typedef enum RegisterSetTag
+ {
+ e_regSetALL = REGISTER_SET_ALL,
+ e_regSetGPR,
+ e_regSetFPU,
+ e_regSetEXC,
+ kNumRegisterSets
+ } RegisterSet;
+
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ struct Context
+ {
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ };
+
+ struct State
+ {
+ Context context;
+ kern_return_t gpr_errs[2]; // Read/Write errors
+ kern_return_t fpu_errs[2]; // Read/Write errors
+ kern_return_t exc_errs[2]; // Read/Write errors
+
+ State()
+ {
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+ }
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (e_regSetALL, Read, -1);
+ }
+
+ kern_return_t
+ 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 e_regSetALL: return gpr_errs[err_idx] |
+ fpu_errs[err_idx] |
+ exc_errs[err_idx];
+ case e_regSetGPR: return gpr_errs[err_idx];
+ case e_regSetFPU: return fpu_errs[err_idx];
+ case e_regSetEXC: return exc_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, kern_return_t err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case e_regSetALL:
+ gpr_errs[err_idx] =
+ fpu_errs[err_idx] =
+ exc_errs[err_idx] = err;
+ return true;
+
+ case e_regSetGPR:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case e_regSetFPU:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case e_regSetEXC:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegsAreValid (int flavor) const
+ {
+ return GetError(flavor, Read) == KERN_SUCCESS;
+ }
+ };
+
+ kern_return_t GetGPRState (bool force);
+ kern_return_t GetFPUState (bool force);
+ kern_return_t GetEXCState (bool force);
+
+ kern_return_t SetGPRState ();
+ kern_return_t SetFPUState ();
+ kern_return_t SetEXCState ();
+
+ MachThread *m_thread;
+ State m_state;
+};
+
+typedef DNBArchImplX86_64 DNBArch;
+
+#endif // #if defined (__x86_64__)
+#endif // #ifndef __DNBArchImplX86_64_h__
diff --git a/lldb/tools/debugserver/source/PThreadCondition.h b/lldb/tools/debugserver/source/PThreadCondition.h
new file mode 100644
index 00000000000..787cc7941d5
--- /dev/null
+++ b/lldb/tools/debugserver/source/PThreadCondition.h
@@ -0,0 +1,53 @@
+//===-- PThreadCondition.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/16/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __PThreadCondition_h__
+#define __PThreadCondition_h__
+
+#include <pthread.h>
+
+class PThreadCondition
+{
+public:
+
+ PThreadCondition()
+ {
+ ::pthread_cond_init (&m_condition, NULL);
+ }
+
+ ~PThreadCondition()
+ {
+ ::pthread_cond_destroy (&m_condition);
+ }
+
+ pthread_cond_t *Condition()
+ {
+ return &m_condition;
+ }
+
+ int Broadcast()
+ {
+ return ::pthread_cond_broadcast (&m_condition);
+ }
+
+ int Signal()
+ {
+ return ::pthread_cond_signal (&m_condition);
+ }
+
+protected:
+ pthread_cond_t m_condition;
+};
+
+#endif
+
diff --git a/lldb/tools/debugserver/source/PThreadEvent.cpp b/lldb/tools/debugserver/source/PThreadEvent.cpp
new file mode 100644
index 00000000000..b087bfc7d48
--- /dev/null
+++ b/lldb/tools/debugserver/source/PThreadEvent.cpp
@@ -0,0 +1,227 @@
+//===-- PThreadEvent.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/16/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PThreadEvent.h"
+#include "errno.h"
+#include "DNBLog.h"
+
+PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits) :
+ m_mutex(),
+ m_set_condition(),
+ m_reset_condition(),
+ m_bits(bits),
+ m_validBits(validBits),
+ m_reset_ack_mask(0)
+{
+ // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)", this, __FUNCTION__, bits, validBits);
+}
+
+PThreadEvent::~PThreadEvent()
+{
+ // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, __PRETTY_FUNCTION__);
+}
+
+
+uint32_t
+PThreadEvent::NewEventBit()
+{
+ // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, __PRETTY_FUNCTION__);
+ PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+ uint32_t mask = 1;
+ while (mask & m_validBits)
+ mask <<= 1;
+ m_validBits |= mask;
+ return mask;
+}
+
+void
+PThreadEvent::FreeEventBits(const uint32_t mask)
+{
+ // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask);
+ if (mask)
+ {
+ PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+ m_bits &= ~mask;
+ m_validBits &= ~mask;
+ }
+}
+
+
+uint32_t
+PThreadEvent::GetEventBits() const
+{
+ // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, __PRETTY_FUNCTION__);
+ PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+ uint32_t bits = m_bits;
+ return bits;
+}
+
+// Replace the event bits with a new bitmask value
+void
+PThreadEvent::ReplaceEventBits(const uint32_t bits)
+{
+ // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, bits);
+ PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+ // Make sure we have some bits and that they aren't already set...
+ if (m_bits != bits)
+ {
+ // Figure out which bits are changing
+ uint32_t changed_bits = m_bits ^ bits;
+ // Set the new bit values
+ m_bits = bits;
+ // If any new bits are set, then broadcast
+ if (changed_bits & m_bits)
+ m_set_condition.Broadcast();
+ }
+}
+
+// Set one or more event bits and broadcast if any new event bits get set
+// that weren't already set.
+
+void
+PThreadEvent::SetEvents(const uint32_t mask)
+{
+ // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask);
+ // Make sure we have some bits to set
+ if (mask)
+ {
+ PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+ // Save the old event bit state so we can tell if things change
+ uint32_t old = m_bits;
+ // Set the all event bits that are set in 'mask'
+ m_bits |= mask;
+ // Broadcast only if any extra bits got set.
+ if (old != m_bits)
+ m_set_condition.Broadcast();
+ }
+}
+
+// Reset one or more event bits
+void
+PThreadEvent::ResetEvents(const uint32_t mask)
+{
+ // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask);
+ if (mask)
+ {
+ PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+
+ // Save the old event bit state so we can tell if things change
+ uint32_t old = m_bits;
+ // Clear the all event bits that are set in 'mask'
+ m_bits &= ~mask;
+ // Broadcast only if any extra bits got reset.
+ if (old != m_bits)
+ m_reset_condition.Broadcast();
+ }
+}
+
+//----------------------------------------------------------------------
+// Wait until 'timeout_abstime' for any events that are set in
+// 'mask'. If 'timeout_abstime' is NULL, then wait forever.
+//----------------------------------------------------------------------
+uint32_t
+PThreadEvent::WaitForSetEvents(const uint32_t mask, const struct timespec *timeout_abstime) const
+{
+ // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime);
+ 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 (PThreadMutex::Locker) to allow us to return at any point in this
+ // function and not have to worry about unlocking the mutex.
+ PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+ do
+ {
+ // Check our predicate (event bits) in case any are already set
+ if (mask & m_bits)
+ {
+ uint32_t bits_set = mask & m_bits;
+ // Our PThreadMutex::Locker will automatically unlock our mutex
+ return bits_set;
+ }
+ if (timeout_abstime)
+ {
+ // Wait for condition to get broadcast, or for a timeout. If we get
+ // a timeout we will drop out of the do loop and return false which
+ // is what we want.
+ err = ::pthread_cond_timedwait (m_set_condition.Condition(), m_mutex.Mutex(), timeout_abstime);
+ // Retest our predicate in case of a race condition right at the end
+ // of the timeout.
+ if (err == ETIMEDOUT)
+ {
+ uint32_t bits_set = mask & m_bits;
+ return bits_set;
+ }
+ }
+ else
+ {
+ // Wait for condition to get broadcast. The only error this function
+ // should return is if
+ err = ::pthread_cond_wait (m_set_condition.Condition(), m_mutex.Mutex());
+ }
+ } while (err == 0);
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Wait until 'timeout_abstime' for any events in 'mask' to reset.
+// If 'timeout_abstime' is NULL, then wait forever.
+//----------------------------------------------------------------------
+uint32_t
+PThreadEvent::WaitForEventsToReset(const uint32_t mask, const struct timespec *timeout_abstime) const
+{
+ // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime);
+ 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 (PThreadMutex::Locker) to allow us to return at any point in this
+ // function and not have to worry about unlocking the mutex.
+ PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+ do
+ {
+ // Check our predicate (event bits) each time through this do loop
+ if ((mask & m_bits) == 0)
+ {
+ // All the bits requested have been reset, return zero indicating
+ // which bits from the mask were still set (none of them)
+ return 0;
+ }
+ if (timeout_abstime)
+ {
+ // Wait for condition to get broadcast, or for a timeout. If we get
+ // a timeout we will drop out of the do loop and return false which
+ // is what we want.
+ err = ::pthread_cond_timedwait (m_reset_condition.Condition(), m_mutex.Mutex(), timeout_abstime);
+ }
+ else
+ {
+ // Wait for condition to get broadcast. The only error this function
+ // should return is if
+ err = ::pthread_cond_wait (m_reset_condition.Condition(), m_mutex.Mutex());
+ }
+ } while (err == 0);
+ // Return a mask indicating which bits (if any) were still set
+ return mask & m_bits;
+}
+
+uint32_t
+PThreadEvent::WaitForResetAck (const uint32_t mask, const struct timespec *timeout_abstime) const
+{
+ if (mask & m_reset_ack_mask)
+ {
+ // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime);
+ return WaitForEventsToReset (mask & m_reset_ack_mask, timeout_abstime);
+ }
+ return 0;
+}
diff --git a/lldb/tools/debugserver/source/PThreadEvent.h b/lldb/tools/debugserver/source/PThreadEvent.h
new file mode 100644
index 00000000000..7928566e8b1
--- /dev/null
+++ b/lldb/tools/debugserver/source/PThreadEvent.h
@@ -0,0 +1,59 @@
+//===-- PThreadEvent.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/16/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __PThreadEvent_h__
+#define __PThreadEvent_h__
+#include "PThreadMutex.h"
+#include "PThreadCondition.h"
+#include <stdint.h>
+#include <time.h>
+
+class PThreadEvent
+{
+public:
+ PThreadEvent (uint32_t bits = 0, uint32_t validBits = 0);
+ ~PThreadEvent ();
+
+ uint32_t NewEventBit ();
+ void FreeEventBits (const uint32_t mask);
+
+ void ReplaceEventBits (const uint32_t bits);
+ uint32_t GetEventBits () const;
+ void SetEvents (const uint32_t mask);
+ void ResetEvents (const uint32_t mask);
+ // Wait for events to be set or reset. These functions take an optional
+ // timeout value. If timeout is NULL an infinite timeout will be used.
+ uint32_t WaitForSetEvents (const uint32_t mask, const struct timespec *timeout_abstime = NULL) const;
+ uint32_t WaitForEventsToReset(const uint32_t mask, const struct timespec *timeout_abstime = NULL) const;
+
+ uint32_t GetResetAckMask () const { return m_reset_ack_mask; }
+ uint32_t SetResetAckMask (uint32_t mask) { return m_reset_ack_mask = mask; }
+ uint32_t WaitForResetAck (const uint32_t mask, const struct timespec *timeout_abstime = NULL) const;
+protected:
+ //----------------------------------------------------------------------
+ // pthread condition and mutex variable to controll access and allow
+ // blocking between the main thread and the spotlight index thread.
+ //----------------------------------------------------------------------
+ mutable PThreadMutex m_mutex;
+ mutable PThreadCondition m_set_condition;
+ mutable PThreadCondition m_reset_condition;
+ uint32_t m_bits;
+ uint32_t m_validBits;
+ uint32_t m_reset_ack_mask;
+private:
+ PThreadEvent(const PThreadEvent&); // Outlaw copy contructor
+ PThreadEvent& operator=(const PThreadEvent& rhs);
+
+};
+
+#endif // #ifndef __PThreadEvent_h__
diff --git a/lldb/tools/debugserver/source/PThreadMutex.cpp b/lldb/tools/debugserver/source/PThreadMutex.cpp
new file mode 100644
index 00000000000..bd91ed0154b
--- /dev/null
+++ b/lldb/tools/debugserver/source/PThreadMutex.cpp
@@ -0,0 +1,84 @@
+//===-- PThreadMutex.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 12/9/08.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PThreadMutex.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "DNBTimer.h"
+
+#if defined (DEBUG_PTHREAD_MUTEX_DEADLOCKS)
+
+PThreadMutex::Locker::Locker(PThreadMutex& m, const char *function, const char *file, const int line) :
+ m_pMutex(m.Mutex()),
+ m_function(function),
+ m_file(file),
+ m_line(line),
+ m_lock_time(0)
+{
+ Lock();
+}
+
+PThreadMutex::Locker::Locker(PThreadMutex* m, const char *function, const char *file, const int line) :
+ m_pMutex(m ? m->Mutex() : NULL),
+ m_function(function),
+ m_file(file),
+ m_line(line),
+ m_lock_time(0)
+{
+ Lock();
+}
+
+PThreadMutex::Locker::Locker(pthread_mutex_t *mutex, const char *function, const char *file, const int line) :
+ m_pMutex(mutex),
+ m_function(function),
+ m_file(file),
+ m_line(line),
+ m_lock_time(0)
+{
+ Lock();
+}
+
+
+PThreadMutex::Locker::~Locker()
+{
+ Unlock();
+}
+
+
+void
+PThreadMutex::Locker::Lock()
+{
+ if (m_pMutex)
+ {
+ m_lock_time = DNBTimer::GetTimeOfDay();
+ if (::pthread_mutex_trylock (m_pMutex) != 0)
+ {
+ fprintf(stdout, "::pthread_mutex_trylock (%8.8p) mutex is locked (function %s in %s:%i), waiting...\n", m_pMutex, m_function, m_file, m_line);
+ ::pthread_mutex_lock (m_pMutex);
+ fprintf(stdout, "::pthread_mutex_lock (%8.8p) succeeded after %6llu usecs (function %s in %s:%i)\n", m_pMutex, DNBTimer::GetTimeOfDay() - m_lock_time, m_function, m_file, m_line);
+ }
+ }
+}
+
+
+void
+PThreadMutex::Locker::Unlock()
+{
+ fprintf(stdout, "::pthread_mutex_unlock (%8.8p) had lock for %6llu usecs in %s in %s:%i\n", m_pMutex, DNBTimer::GetTimeOfDay() - m_lock_time, m_function, m_file, m_line);
+ ::pthread_mutex_unlock (m_pMutex);
+}
+
+#endif
diff --git a/lldb/tools/debugserver/source/PThreadMutex.h b/lldb/tools/debugserver/source/PThreadMutex.h
new file mode 100644
index 00000000000..9a12f6e8e03
--- /dev/null
+++ b/lldb/tools/debugserver/source/PThreadMutex.h
@@ -0,0 +1,148 @@
+//===-- PThreadMutex.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/16/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __PThreadMutex_h__
+#define __PThreadMutex_h__
+
+#include <pthread.h>
+#include <assert.h>
+#include <stdint.h>
+
+//#define DEBUG_PTHREAD_MUTEX_DEADLOCKS 1
+
+#if defined (DEBUG_PTHREAD_MUTEX_DEADLOCKS)
+#define PTHREAD_MUTEX_LOCKER(var, mutex) PThreadMutex::Locker var(mutex, __FUNCTION__, __FILE__, __LINE__)
+
+#else
+#define PTHREAD_MUTEX_LOCKER(var, mutex) PThreadMutex::Locker var(mutex)
+#endif
+
+class PThreadMutex
+{
+public:
+
+ class Locker
+ {
+ public:
+#if defined (DEBUG_PTHREAD_MUTEX_DEADLOCKS)
+
+ Locker(PThreadMutex& m, const char *function, const char *file, int line);
+ Locker(PThreadMutex* m, const char *function, const char *file, int line);
+ Locker(pthread_mutex_t *mutex, const char *function, const char *file, int line);
+ ~Locker();
+ void Lock();
+ void Unlock();
+
+#else
+ Locker(PThreadMutex& m) :
+ m_pMutex(m.Mutex())
+ {
+ Lock();
+ }
+
+ Locker(PThreadMutex* m) :
+ m_pMutex(m ? m->Mutex() : NULL)
+ {
+ Lock();
+ }
+
+ Locker(pthread_mutex_t *mutex) :
+ m_pMutex(mutex)
+ {
+ Lock();
+ }
+
+ void Lock()
+ {
+ if (m_pMutex)
+ ::pthread_mutex_lock (m_pMutex);
+ }
+
+ void Unlock()
+ {
+ if (m_pMutex)
+ ::pthread_mutex_unlock (m_pMutex);
+ }
+
+ ~Locker()
+ {
+ Unlock();
+ }
+
+#endif
+
+ // unlock any the current mutex and lock the new one if it is valid
+ void Reset(pthread_mutex_t *pMutex = NULL)
+ {
+ Unlock();
+ m_pMutex = pMutex;
+ Lock();
+ }
+ pthread_mutex_t *m_pMutex;
+#if defined (DEBUG_PTHREAD_MUTEX_DEADLOCKS)
+ const char *m_function;
+ const char *m_file;
+ int m_line;
+ uint64_t m_lock_time;
+#endif
+ };
+
+
+ PThreadMutex()
+ {
+ int err;
+ err = ::pthread_mutex_init (&m_mutex, NULL); assert(err == 0);
+ }
+
+ PThreadMutex(int type)
+ {
+ int err;
+ ::pthread_mutexattr_t attr;
+ err = ::pthread_mutexattr_init (&attr); assert(err == 0);
+ err = ::pthread_mutexattr_settype (&attr, type); assert(err == 0);
+ err = ::pthread_mutex_init (&m_mutex, &attr); assert(err == 0);
+ err = ::pthread_mutexattr_destroy (&attr); assert(err == 0);
+ }
+
+ ~PThreadMutex()
+ {
+ int err;
+ err = ::pthread_mutex_destroy (&m_mutex);
+ if (err != 0)
+ {
+ err = Unlock();
+ if (err == 0)
+ ::pthread_mutex_destroy (&m_mutex);
+ }
+ }
+
+ pthread_mutex_t *Mutex()
+ {
+ return &m_mutex;
+ }
+
+ int Lock()
+ {
+ return ::pthread_mutex_lock (&m_mutex);
+ }
+
+ int Unlock()
+ {
+ return ::pthread_mutex_unlock (&m_mutex);
+ }
+
+protected:
+ pthread_mutex_t m_mutex;
+};
+
+#endif
diff --git a/lldb/tools/debugserver/source/ProfileObjectiveC.cpp b/lldb/tools/debugserver/source/ProfileObjectiveC.cpp
new file mode 100644
index 00000000000..1fd2d526d25
--- /dev/null
+++ b/lldb/tools/debugserver/source/ProfileObjectiveC.cpp
@@ -0,0 +1,393 @@
+//===-- ProfileObjectiveC.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 10/4/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProfileObjectiveC.h"
+#include "DNB.h"
+#include <objc/objc-runtime.h>
+#include <map>
+
+#if defined (__powerpc__) || defined (__ppc__)
+#define OBJC_MSG_SEND_PPC32_COMM_PAGE_ADDR ((nub_addr_t)0xfffeff00)
+#endif
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+ProfileObjectiveC::ProfileObjectiveC() :
+ m_pid(INVALID_NUB_PROCESS),
+ m_objcStats(),
+ m_hit_count(0),
+ m_dump_count(0xffff)
+{
+ memset(&m_begin_time, 0, sizeof(m_begin_time));
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProfileObjectiveC::~ProfileObjectiveC()
+{
+}
+
+//----------------------------------------------------------------------
+// Clear any counts that we may have had
+//----------------------------------------------------------------------
+void
+ProfileObjectiveC::Clear()
+{
+ if (m_pid != INVALID_NUB_PROCESS)
+ {
+ DNBBreakpointClear(m_pid, m_objc_msgSend.breakID);
+ DNBBreakpointClear(m_pid, m_objc_msgSendSuper.breakID);
+#if defined (__powerpc__) || defined (__ppc__)
+ DNBBreakpointClear(m_pid, m_objc_msgSend_rtp.breakID);
+#endif
+ }
+ m_objc_msgSend.Clear();
+ m_objc_msgSendSuper.Clear();
+#if defined (__powerpc__) || defined (__ppc__)
+ memset(m_objc_msgSend_opcode, 0, k_opcode_size);
+ m_objc_msgSend_rtp.Clear();
+#endif
+ memset(&m_begin_time, 0, sizeof(m_begin_time));
+ m_objcStats.clear();
+}
+
+void
+ProfileObjectiveC::Initialize(nub_process_t pid)
+{
+ Clear();
+ m_pid = pid;
+}
+
+
+void
+ProfileObjectiveC::ProcessStateChanged(nub_state_t state)
+{
+ //printf("ProfileObjectiveC::%s(%s)\n", __FUNCTION__, DNBStateAsString(state));
+ switch (state)
+ {
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateExited:
+ case eStateDetached:
+ Clear();
+ break;
+
+ case eStateStopped:
+#if defined (__powerpc__) || defined (__ppc__)
+ if (NUB_BREAK_ID_IS_VALID(m_objc_msgSend.breakID) && !NUB_BREAK_ID_IS_VALID(m_objc_msgSend_rtp.breakID))
+ {
+ nub_thread_t tid = DNBProcessGetCurrentThread(m_pid);
+ DNBRegisterValue pc_value;
+ if (DNBThreadGetRegisterValueByName(m_pid, tid, REGISTER_SET_ALL, "srr0" , &pc_value))
+ {
+ nub_addr_t pc = pc_value.value.uint32;
+ if (pc == OBJC_MSG_SEND_PPC32_COMM_PAGE_ADDR)
+ {
+ // Restore previous first instruction to 0xfffeff00 in comm page
+ DNBProcessMemoryWrite(m_pid, OBJC_MSG_SEND_PPC32_COMM_PAGE_ADDR, k_opcode_size, m_objc_msgSend_opcode);
+ //printf("Setting breakpoint on _objc_msgSend_rtp...\n");
+ m_objc_msgSend_rtp.breakID = DNBBreakpointSet(m_pid, OBJC_MSG_SEND_PPC32_COMM_PAGE_ADDR);
+ if (NUB_BREAK_ID_IS_VALID(m_objc_msgSend_rtp.breakID))
+ {
+ DNBBreakpointSetCallback(m_pid, m_objc_msgSend_rtp.breakID, ProfileObjectiveC::MessageSendBreakpointCallback, this);
+ }
+ }
+ }
+ }
+#endif
+ DumpStats(m_pid, stdout);
+ break;
+
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateCrashed:
+ case eStateSuspended:
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+ProfileObjectiveC::SharedLibraryStateChanged(DNBExecutableImageInfo *image_infos, nub_size_t num_image_infos)
+{
+ //printf("ProfileObjectiveC::%s(%p, %u)\n", __FUNCTION__, image_infos, num_image_infos);
+ if (m_objc_msgSend.IsValid() && m_objc_msgSendSuper.IsValid())
+ return;
+
+ if (image_infos)
+ {
+ nub_process_t pid = m_pid;
+ nub_size_t i;
+ for (i = 0; i < num_image_infos; i++)
+ {
+ if (strcmp(image_infos[i].name, "/usr/lib/libobjc.A.dylib") == 0)
+ {
+ if (!NUB_BREAK_ID_IS_VALID(m_objc_msgSend.breakID))
+ {
+ m_objc_msgSend.addr = DNBProcessLookupAddress(pid, "_objc_msgSend", image_infos[i].name);
+
+ if (m_objc_msgSend.addr != INVALID_NUB_ADDRESS)
+ {
+#if defined (__powerpc__) || defined (__ppc__)
+ if (DNBProcessMemoryRead(pid, m_objc_msgSend.addr, k_opcode_size, m_objc_msgSend_opcode) != k_opcode_size)
+ memset(m_objc_msgSend_opcode, 0, sizeof(m_objc_msgSend_opcode));
+#endif
+ m_objc_msgSend.breakID = DNBBreakpointSet(pid, m_objc_msgSend.addr, 4, false);
+ if (NUB_BREAK_ID_IS_VALID(m_objc_msgSend.breakID))
+ DNBBreakpointSetCallback(pid, m_objc_msgSend.breakID, ProfileObjectiveC::MessageSendBreakpointCallback, this);
+ }
+ }
+
+ if (!NUB_BREAK_ID_IS_VALID(m_objc_msgSendSuper.breakID))
+ {
+ m_objc_msgSendSuper.addr = DNBProcessLookupAddress(pid, "_objc_msgSendSuper", image_infos[i].name);
+
+ if (m_objc_msgSendSuper.addr != INVALID_NUB_ADDRESS)
+ {
+ m_objc_msgSendSuper.breakID = DNBBreakpointSet(pid, m_objc_msgSendSuper.addr, 4, false);
+ if (NUB_BREAK_ID_IS_VALID(m_objc_msgSendSuper.breakID))
+ DNBBreakpointSetCallback(pid, m_objc_msgSendSuper.breakID, ProfileObjectiveC::MessageSendSuperBreakpointCallback, this);
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+void
+ProfileObjectiveC::SetStartTime()
+{
+ gettimeofday(&m_begin_time, NULL);
+}
+
+void
+ProfileObjectiveC::SelectorHit(objc_class_ptr_t isa, objc_selector_t sel)
+{
+ m_objcStats[isa][sel]++;
+}
+
+nub_bool_t
+ProfileObjectiveC::MessageSendBreakpointCallback(nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *userData)
+{
+ ProfileObjectiveC *profile_objc = (ProfileObjectiveC*)userData;
+ uint32_t hit_count = profile_objc->IncrementHitCount();
+ if (hit_count == 1)
+ profile_objc->SetStartTime();
+
+ objc_class_ptr_t objc_self = 0;
+ objc_selector_t objc_selector = 0;
+#if defined (__i386__)
+ DNBRegisterValue esp;
+ if (DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, "esp", &esp))
+ {
+ uint32_t uval32[2];
+ if (DNBProcessMemoryRead(pid, esp.value.uint32 + 4, 8, &uval32) == 8)
+ {
+ objc_self = uval32[0];
+ objc_selector = uval32[1];
+ }
+ }
+#elif defined (__powerpc__) || defined (__ppc__)
+ DNBRegisterValue r3;
+ DNBRegisterValue r4;
+ if (DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, "r3", &r3) &&
+ DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, "r4", &r4))
+ {
+ objc_self = r3.value.uint32;
+ objc_selector = r4.value.uint32;
+ }
+#elif defined (__arm__)
+ DNBRegisterValue r0;
+ DNBRegisterValue r1;
+ if (DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, "r0", &r0) &&
+ DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, "r1", &r1))
+ {
+ objc_self = r0.value.uint32;
+ objc_selector = r1.value.uint32;
+ }
+#else
+#error undefined architecture
+#endif
+ if (objc_selector != 0)
+ {
+ uint32_t isa = 0;
+ if (objc_self == 0)
+ {
+ profile_objc->SelectorHit(0, objc_selector);
+ }
+ else
+ if (DNBProcessMemoryRead(pid, (nub_addr_t)objc_self, sizeof(isa), &isa) == sizeof(isa))
+ {
+ if (isa)
+ {
+ profile_objc->SelectorHit(isa, objc_selector);
+ }
+ else
+ {
+ profile_objc->SelectorHit(0, objc_selector);
+ }
+ }
+ }
+
+
+ // Dump stats if we are supposed to
+ if (profile_objc->ShouldDumpStats())
+ {
+ profile_objc->DumpStats(pid, stdout);
+ return true;
+ }
+
+ // Just let the target run again by returning false;
+ return false;
+}
+
+nub_bool_t
+ProfileObjectiveC::MessageSendSuperBreakpointCallback(nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *userData)
+{
+ ProfileObjectiveC *profile_objc = (ProfileObjectiveC*)userData;
+
+ uint32_t hit_count = profile_objc->IncrementHitCount();
+ if (hit_count == 1)
+ profile_objc->SetStartTime();
+
+// printf("BreakID %u hit count is = %u\n", breakID, hc);
+ objc_class_ptr_t objc_super = 0;
+ objc_selector_t objc_selector = 0;
+#if defined (__i386__)
+ DNBRegisterValue esp;
+ if (DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, "esp", &esp))
+ {
+ uint32_t uval32[2];
+ if (DNBProcessMemoryRead(pid, esp.value.uint32 + 4, 8, &uval32) == 8)
+ {
+ objc_super = uval32[0];
+ objc_selector = uval32[1];
+ }
+ }
+#elif defined (__powerpc__) || defined (__ppc__)
+ DNBRegisterValue r3;
+ DNBRegisterValue r4;
+ if (DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, "r3", &r3) &&
+ DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, "r4", &r4))
+ {
+ objc_super = r3.value.uint32;
+ objc_selector = r4.value.uint32;
+ }
+#elif defined (__arm__)
+ DNBRegisterValue r0;
+ DNBRegisterValue r1;
+ if (DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, "r0", &r0) &&
+ DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, "r1", &r1))
+ {
+ objc_super = r0.value.uint32;
+ objc_selector = r1.value.uint32;
+ }
+#else
+#error undefined architecture
+#endif
+ if (objc_selector != 0)
+ {
+ uint32_t isa = 0;
+ if (objc_super == 0)
+ {
+ profile_objc->SelectorHit(0, objc_selector);
+ }
+ else
+ if (DNBProcessMemoryRead(pid, (nub_addr_t)objc_super + 4, sizeof(isa), &isa) == sizeof(isa))
+ {
+ if (isa)
+ {
+ profile_objc->SelectorHit(isa, objc_selector);
+ }
+ else
+ {
+ profile_objc->SelectorHit(0, objc_selector);
+ }
+ }
+ }
+
+ // Dump stats if we are supposed to
+ if (profile_objc->ShouldDumpStats())
+ {
+ profile_objc->DumpStats(pid, stdout);
+ return true;
+ }
+
+ // Just let the target run again by returning false;
+ return false;
+}
+
+void
+ProfileObjectiveC::DumpStats(nub_process_t pid, FILE *f)
+{
+ if (f == NULL)
+ return;
+
+ if (m_hit_count == 0)
+ return;
+
+ ClassStatsMap::iterator class_pos;
+ ClassStatsMap::iterator class_end = m_objcStats.end();
+
+ struct timeval end_time;
+ gettimeofday(&end_time, NULL);
+ int64_t elapsed_usec = ((int64_t)(1000*1000))*((int64_t)end_time.tv_sec - (int64_t)m_begin_time.tv_sec) + ((int64_t)end_time.tv_usec - (int64_t)m_begin_time.tv_usec);
+ fprintf(f, "%u probe hits for %.2f hits/sec)\n", m_hit_count, (double)m_hit_count / (((double)elapsed_usec)/(1000000.0)));
+
+ for (class_pos = m_objcStats.begin(); class_pos != class_end; ++class_pos)
+ {
+ SelectorHitCount::iterator sel_pos;
+ SelectorHitCount::iterator sel_end = class_pos->second.end();
+ for (sel_pos = class_pos->second.begin(); sel_pos != sel_end; ++sel_pos)
+ {
+ struct objc_class objc_class;
+ uint32_t isa = class_pos->first;
+ uint32_t sel = sel_pos->first;
+ uint32_t sel_hit_count = sel_pos->second;
+
+ if (isa != 0 && DNBProcessMemoryRead(pid, isa, sizeof(objc_class), &objc_class) == sizeof(objc_class))
+ {
+ /* fprintf(f, "%#.8x\n isa = %p\n super_class = %p\n name = %p\n version = %lx\n info = %lx\ninstance_size = %lx\n ivars = %p\n methodLists = %p\n cache = %p\n protocols = %p\n",
+ arg1.value.pointer,
+ objc_class.isa,
+ objc_class.super_class,
+ objc_class.name,
+ objc_class.version,
+ objc_class.info,
+ objc_class.instance_size,
+ objc_class.ivars,
+ objc_class.methodLists,
+ objc_class.cache,
+ objc_class.protocols); */
+
+ // Print the class name
+ fprintf(f, "%6u hits for %c[", sel_hit_count, (objc_class.super_class == objc_class.isa ? '+' : '-'));
+ DNBPrintf(pid, INVALID_NUB_THREAD, (nub_addr_t)objc_class.name, f, "%s ");
+ }
+ else
+ {
+ fprintf(f, "%6u hits for [<nil> ", sel_hit_count);
+ }
+ DNBPrintf(pid, INVALID_NUB_THREAD, sel, f, "%s]\n");
+ }
+ }
+}
+
diff --git a/lldb/tools/debugserver/source/ProfileObjectiveC.h b/lldb/tools/debugserver/source/ProfileObjectiveC.h
new file mode 100644
index 00000000000..8a5c13db32a
--- /dev/null
+++ b/lldb/tools/debugserver/source/ProfileObjectiveC.h
@@ -0,0 +1,82 @@
+//===-- ProfileObjectiveC.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 10/4/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __ProfileObjectiveC_h__
+#define __ProfileObjectiveC_h__
+
+#include "DNB.h"
+#include "DNBRuntimeAction.h"
+#include <map>
+#include <sys/time.h>
+
+class ProfileObjectiveC : public DNBRuntimeAction
+{
+public:
+ ProfileObjectiveC();
+ virtual ~ProfileObjectiveC();
+ //------------------------------------------------------------------
+ // DNBRuntimeAction required functions
+ //------------------------------------------------------------------
+ virtual void Initialize(nub_process_t pid);
+ virtual void ProcessStateChanged(nub_state_t state);
+ virtual void SharedLibraryStateChanged(DNBExecutableImageInfo *image_infos, nub_size_t num_image_infos);
+
+protected:
+ typedef uint32_t objc_selector_t;
+ typedef uint32_t objc_class_ptr_t;
+ void Clear();
+ static nub_bool_t MessageSendBreakpointCallback(nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *userData);
+ static nub_bool_t MessageSendSuperBreakpointCallback(nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *userData);
+ void DumpStats(nub_process_t pid, FILE *f);
+ void SetStartTime();
+ void SelectorHit(objc_class_ptr_t isa, objc_selector_t sel);
+ typedef std::map<objc_selector_t, uint32_t> SelectorHitCount;
+ typedef std::map<objc_class_ptr_t, SelectorHitCount> ClassStatsMap;
+ typedef struct Probe
+ {
+ nub_addr_t addr;
+ nub_break_t breakID;
+ Probe() : addr(INVALID_NUB_ADDRESS), breakID(INVALID_NUB_BREAK_ID) {}
+ void Clear()
+ {
+ addr = INVALID_NUB_ADDRESS;
+ breakID = INVALID_NUB_BREAK_ID;
+ }
+ bool IsValid() const
+ {
+ return (addr != INVALID_NUB_ADDRESS) && (NUB_BREAK_ID_IS_VALID(breakID));
+ }
+ };
+
+ uint32_t IncrementHitCount() { return ++m_hit_count; }
+ bool ShouldDumpStats() const { return m_dump_count && (m_hit_count % m_dump_count) == 0; }
+
+ nub_process_t m_pid;
+ Probe m_objc_msgSend;
+ Probe m_objc_msgSendSuper;
+ uint32_t m_hit_count; // Number of times we have gotten one of our breakpoints hit
+ uint32_t m_dump_count; // Dump stats every time the hit count reaches a multiple of this value
+#if defined (__powerpc__) || defined (__ppc__)
+ enum
+ {
+ k_opcode_size = 4
+ };
+ uint8_t m_objc_msgSend_opcode[k_opcode_size]; // Saved copy of first opcode in objc_msgSend
+ Probe m_objc_msgSend_rtp; // COMM page probe info for objc_msgSend
+#endif
+ struct timeval m_begin_time;
+ ClassStatsMap m_objcStats;
+};
+
+
+#endif // #ifndef __ProfileObjectiveC_h__
diff --git a/lldb/tools/debugserver/source/PseudoTerminal.cpp b/lldb/tools/debugserver/source/PseudoTerminal.cpp
new file mode 100644
index 00000000000..278ab88828a
--- /dev/null
+++ b/lldb/tools/debugserver/source/PseudoTerminal.cpp
@@ -0,0 +1,226 @@
+//===-- PseudoTerminal.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 1/8/08.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PseudoTerminal.h"
+#include <stdlib.h>
+#include <sys/ioctl.h>
+
+//----------------------------------------------------------------------
+// PseudoTerminal constructor
+//----------------------------------------------------------------------
+PseudoTerminal::PseudoTerminal() :
+ m_master_fd(invalid_fd),
+ m_slave_fd(invalid_fd)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+// The master and slave file descriptors will get closed if they are
+// valid. Call the ReleaseMasterFD()/ReleaseSlaveFD() member functions
+// to release any file descriptors that are needed beyond the lifespan
+// of this object.
+//----------------------------------------------------------------------
+PseudoTerminal::~PseudoTerminal()
+{
+ CloseMaster();
+ CloseSlave();
+}
+
+//----------------------------------------------------------------------
+// Close the master file descriptor if it is valid.
+//----------------------------------------------------------------------
+void
+PseudoTerminal::CloseMaster()
+{
+ 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::CloseSlave()
+{
+ 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 store in the m_master_fd member
+// variable and can be accessed via the MasterFD() or ReleaseMasterFD()
+// accessors.
+//
+// Suggested value for oflag is O_RDWR|O_NOCTTY
+//
+// RETURNS:
+// Zero when successful, non-zero indicating an error occurred.
+//----------------------------------------------------------------------
+PseudoTerminal::Error
+PseudoTerminal::OpenFirstAvailableMaster(int oflag)
+{
+ // Open the master side of a pseudo terminal
+ m_master_fd = ::posix_openpt (oflag);
+ if (m_master_fd < 0)
+ {
+ return err_posix_openpt_failed;
+ }
+
+ // Grant access to the slave pseudo terminal
+ if (::grantpt (m_master_fd) < 0)
+ {
+ CloseMaster();
+ return err_grantpt_failed;
+ }
+
+ // Clear the lock flag on the slave pseudo terminal
+ if (::unlockpt (m_master_fd) < 0)
+ {
+ CloseMaster();
+ return err_unlockpt_failed;
+ }
+
+ return success;
+}
+
+//----------------------------------------------------------------------
+// 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 PseudoTerminal::OpenFirstAvailableMaster()).
+// The file descriptor is stored in the m_slave_fd member variable and
+// can be accessed via the SlaveFD() or ReleaseSlaveFD() accessors.
+//
+// RETURNS:
+// Zero when successful, non-zero indicating an error occurred.
+//----------------------------------------------------------------------
+PseudoTerminal::Error
+PseudoTerminal::OpenSlave(int oflag)
+{
+ CloseSlave();
+
+ // Open the master side of a pseudo terminal
+ const char *slave_name = SlaveName();
+
+ if (slave_name == NULL)
+ return err_ptsname_failed;
+
+ m_slave_fd = ::open (slave_name, oflag);
+
+ if (m_slave_fd < 0)
+ return err_open_slave_failed;
+
+ return success;
+}
+
+
+
+//----------------------------------------------------------------------
+// Get the name of the slave pseudo terminal. A master pseudo terminal
+// should already be valid prior to calling this function (see
+// PseudoTerminal::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::SlaveName() const
+{
+ if (m_master_fd < 0)
+ return NULL;
+ return ::ptsname (m_master_fd);
+}
+
+
+//----------------------------------------------------------------------
+// Fork a child process that 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 ReleaseMasterFD()
+// or ReleaseSlaveFD() 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
+//----------------------------------------------------------------------
+
+pid_t
+PseudoTerminal::Fork(PseudoTerminal::Error& error)
+{
+ pid_t pid = invalid_pid;
+ error = OpenFirstAvailableMaster (O_RDWR|O_NOCTTY);
+
+ if (error == 0)
+ {
+ // Successfully opened our master pseudo terminal
+
+ pid = ::fork ();
+ if (pid < 0)
+ {
+ // Fork failed
+ error = err_fork_failed;
+ }
+ else if (pid == 0)
+ {
+ // Child Process
+ ::setsid();
+
+ error = OpenSlave (O_RDWR);
+ if (error == 0)
+ {
+ // Successfully opened slave
+ // We are done with the master in the child process so lets close it
+ CloseMaster ();
+
+#if defined (TIOCSCTTY)
+ // Acquire the controlling terminal
+ if (::ioctl (m_slave_fd, TIOCSCTTY, (char *)0) < 0)
+ error = err_failed_to_acquire_controlling_terminal;
+#endif
+ // Duplicate all stdio file descriptors to the slave pseudo terminal
+ if (::dup2 (m_slave_fd, STDIN_FILENO) != STDIN_FILENO)
+ error = error ? error : err_dup2_failed_on_stdin;
+ if (::dup2 (m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO)
+ error = error ? error : err_dup2_failed_on_stdout;
+ if (::dup2 (m_slave_fd, STDERR_FILENO) != STDERR_FILENO)
+ error = error ? error : err_dup2_failed_on_stderr;
+ }
+ }
+ else
+ {
+ // Parent Process
+ // Do nothing and let the pid get returned!
+ }
+ }
+ return pid;
+}
diff --git a/lldb/tools/debugserver/source/PseudoTerminal.h b/lldb/tools/debugserver/source/PseudoTerminal.h
new file mode 100644
index 00000000000..1f09b417452
--- /dev/null
+++ b/lldb/tools/debugserver/source/PseudoTerminal.h
@@ -0,0 +1,94 @@
+//===-- PseudoTerminal.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 1/8/08.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __PseudoTerminal_h__
+#define __PseudoTerminal_h__
+
+#include <fcntl.h>
+#include <termios.h>
+#include <string>
+
+class PseudoTerminal
+{
+public:
+ enum {
+ invalid_fd = -1,
+ invalid_pid = -1
+ };
+
+ typedef enum Error
+ {
+ success = 0,
+ err_posix_openpt_failed = -2,
+ err_grantpt_failed = -3,
+ err_unlockpt_failed = -4,
+ err_ptsname_failed = -5,
+ err_open_slave_failed = -6,
+ err_fork_failed = -7,
+ err_setsid_failed = -8,
+ err_failed_to_acquire_controlling_terminal = -9,
+ err_dup2_failed_on_stdin = -10,
+ err_dup2_failed_on_stdout = -11,
+ err_dup2_failed_on_stderr = -12
+ };
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ PseudoTerminal ();
+ ~PseudoTerminal ();
+
+ void CloseMaster ();
+ void CloseSlave ();
+ Error OpenFirstAvailableMaster (int oflag);
+ Error OpenSlave (int oflag);
+ int MasterFD () const { return m_master_fd; }
+ int SlaveFD () const { return m_slave_fd; }
+ int ReleaseMasterFD ()
+ {
+ // 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;
+ }
+ int ReleaseSlaveFD ()
+ {
+ // 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;
+ }
+
+ const char* SlaveName () const;
+
+ pid_t Fork(Error& error);
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from PseudoTerminal can see and modify these
+ //------------------------------------------------------------------
+ int m_master_fd;
+ int m_slave_fd;
+
+private:
+ //------------------------------------------------------------------
+ // Outlaw copy and assignment constructors
+ //------------------------------------------------------------------
+ PseudoTerminal(const PseudoTerminal& rhs);
+ PseudoTerminal& operator=(const PseudoTerminal& rhs);
+
+};
+
+#endif // #ifndef __PseudoTerminal_h__
diff --git a/lldb/tools/debugserver/source/RNBContext.cpp b/lldb/tools/debugserver/source/RNBContext.cpp
new file mode 100644
index 00000000000..7ef9d32c74e
--- /dev/null
+++ b/lldb/tools/debugserver/source/RNBContext.cpp
@@ -0,0 +1,230 @@
+//===-- RNBContext.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 12/12/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RNBContext.h"
+#include "RNBRemote.h"
+#include "DNB.h"
+#include "DNBLog.h"
+#include "CFString.h"
+#include <sstream>
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RNBContext::~RNBContext()
+{
+ SetProcessID (INVALID_NUB_PROCESS);
+}
+
+//----------------------------------------------------------------------
+// RNBContext constructor
+//----------------------------------------------------------------------
+
+const char *
+RNBContext::EnvironmentAtIndex (int index)
+{
+ if (index < m_env_vec.size())
+ return m_env_vec[index].c_str();
+ else
+ return NULL;
+}
+
+
+const char *
+RNBContext::ArgumentAtIndex (int index)
+{
+ if (index < m_arg_vec.size())
+ return m_arg_vec[index].c_str();
+ else
+ return NULL;
+}
+
+void
+RNBContext::SetProcessID (nub_process_t pid)
+{
+ // Delete and events we created
+ if (m_pid != INVALID_NUB_PROCESS)
+ {
+ StopProcessStatusThread ();
+ // Unregister this context as a client of the process's events.
+ }
+ // Assign our new process ID
+ m_pid = pid;
+
+ if (pid != INVALID_NUB_PROCESS)
+ {
+ StartProcessStatusThread ();
+ }
+}
+
+void
+RNBContext::StartProcessStatusThread()
+{
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__);
+ if ((m_events.GetEventBits() & event_proc_thread_running) == 0)
+ {
+ int err = ::pthread_create (&m_pid_pthread, NULL, ThreadFunctionProcessStatus, this);
+ if (err == 0)
+ {
+ // Our thread was successfully kicked off, wait for it to
+ // set the started event so we can safely continue
+ m_events.WaitForSetEvents (event_proc_thread_running);
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread got started!", __FUNCTION__);
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread failed to start: err = %i", __FUNCTION__, err);
+ m_events.ResetEvents (event_proc_thread_running);
+ m_events.SetEvents (event_proc_thread_exiting);
+ }
+ }
+}
+
+void
+RNBContext::StopProcessStatusThread()
+{
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__);
+ if ((m_events.GetEventBits() & event_proc_thread_running) == event_proc_thread_running)
+ {
+ struct timespec timeout_abstime;
+ DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0);
+ // Wait for 2 seconds for the rx thread to exit
+ if (m_events.WaitForSetEvents(RNBContext::event_proc_thread_exiting, &timeout_abstime) == RNBContext::event_proc_thread_exiting)
+ {
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread stopped as requeseted", __FUNCTION__);
+ }
+ else
+ {
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread did not stop in 2 seconds...", __FUNCTION__);
+ // Kill the RX thread???
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// This thread's sole purpose is to watch for any status changes in the
+// child process.
+//----------------------------------------------------------------------
+void*
+RNBContext::ThreadFunctionProcessStatus(void *arg)
+{
+ RNBRemoteSP remoteSP(g_remoteSP);
+ RNBRemote* remote = remoteSP.get();
+ if (remote == NULL)
+ return NULL;
+ RNBContext& ctx = remote->Context();
+
+ nub_process_t pid = ctx.ProcessID();
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread starting...", __FUNCTION__, arg, pid);
+ ctx.Events().SetEvents (RNBContext::event_proc_thread_running);
+ bool done = false;
+ while (!done)
+ {
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true)...", __FUNCTION__);
+ nub_event_t pid_status_event = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true, NULL);
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true) => 0x%8.8x", __FUNCTION__, pid_status_event);
+
+ if (pid_status_event == 0)
+ {
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got ZERO back from DNBProcessWaitForEvent....", __FUNCTION__, pid);
+ // done = true;
+ }
+ else
+ {
+ if (pid_status_event & eEventStdioAvailable)
+ {
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got stdio available event....", __FUNCTION__, pid);
+ ctx.Events().SetEvents (RNBContext::event_proc_stdio_available);
+ // Wait for the main thread to consume this notification if it requested we wait for it
+ ctx.Events().WaitForResetAck(RNBContext::event_proc_stdio_available);
+ }
+
+
+ if (pid_status_event & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
+ {
+ nub_state_t pid_state = DNBProcessGetState(pid);
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got process state change: %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
+
+ // Let the main thread know there is a process state change to see
+ ctx.Events().SetEvents (RNBContext::event_proc_state_changed);
+ // Wait for the main thread to consume this notification if it requested we wait for it
+ ctx.Events().WaitForResetAck(RNBContext::event_proc_state_changed);
+
+ switch (pid_state)
+ {
+ case eStateStopped:
+ break;
+
+ case eStateInvalid:
+ case eStateExited:
+ done = true;
+ break;
+ }
+ }
+
+ // Reset any events that we consumed.
+ DNBProcessResetEvents(pid, pid_status_event);
+
+ }
+ }
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...", __FUNCTION__, arg, pid);
+ ctx.Events().ResetEvents(event_proc_thread_running);
+ ctx.Events().SetEvents(event_proc_thread_exiting);
+ return NULL;
+}
+
+
+const char*
+RNBContext::EventsAsString (nub_event_t events, std::string& s)
+{
+ s.clear();
+ if (events & event_proc_state_changed)
+ s += "proc_state_changed ";
+ if (events & event_proc_thread_running)
+ s += "proc_thread_running ";
+ if (events & event_proc_thread_exiting)
+ s += "proc_thread_exiting ";
+ if (events & event_proc_stdio_available)
+ s += "proc_stdio_available ";
+ if (events & event_read_packet_available)
+ s += "read_packet_available ";
+ if (events & event_read_thread_running)
+ s += "read_thread_running ";
+ if (events & event_read_thread_running)
+ s += "read_thread_running ";
+ return s.c_str();
+}
+
+const char *
+RNBContext::LaunchStatusAsString (std::string& s)
+{
+ s.clear();
+
+ const char *err_str = m_launch_status.AsString();
+ if (err_str)
+ s = err_str;
+ else
+ {
+ char error_num_str[64];
+ snprintf(error_num_str, sizeof(error_num_str), "%u", m_launch_status.Error());
+ s = error_num_str;
+ }
+ return s.c_str();
+}
+
+bool
+RNBContext::ProcessStateRunning() const
+{
+ nub_state_t pid_state = DNBProcessGetState(m_pid);
+ return pid_state == eStateRunning || pid_state == eStateStepping;
+}
diff --git a/lldb/tools/debugserver/source/RNBContext.h b/lldb/tools/debugserver/source/RNBContext.h
new file mode 100644
index 00000000000..4b5f5ae2cc9
--- /dev/null
+++ b/lldb/tools/debugserver/source/RNBContext.h
@@ -0,0 +1,123 @@
+//===-- RNBContext.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 12/12/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __RNBContext_h__
+#define __RNBContext_h__
+
+#include "RNBDefs.h"
+#include "DNBError.h"
+#include "PThreadEvent.h"
+#include <vector>
+#include <string>
+
+class RNBContext
+{
+public:
+ enum
+ {
+ event_proc_state_changed = 0x01,
+ event_proc_thread_running = 0x02, // Sticky
+ event_proc_thread_exiting = 0x04,
+ event_proc_stdio_available = 0x08,
+ event_read_packet_available = 0x10,
+ event_read_thread_running = 0x20, // Sticky
+ event_read_thread_exiting = 0x40,
+
+ normal_event_bits = event_proc_state_changed |
+ event_proc_thread_exiting |
+ event_proc_stdio_available |
+ event_read_packet_available |
+ event_read_thread_exiting,
+
+ sticky_event_bits = event_proc_thread_running |
+ event_read_thread_running,
+
+
+ all_event_bits = sticky_event_bits | normal_event_bits
+ } event_t;
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RNBContext () :
+ m_pid(INVALID_NUB_PROCESS),
+ m_pid_stop_count(0),
+ m_events(0, all_event_bits),
+ m_pid_pthread(),
+ m_launch_status(),
+ m_arg_vec (),
+ m_env_vec ()
+ {
+ }
+
+ virtual ~RNBContext();
+
+
+ nub_process_t ProcessID() const { return m_pid; }
+ bool HasValidProcessID() const { return m_pid != INVALID_NUB_PROCESS; }
+ void SetProcessID (nub_process_t pid);
+ nub_size_t GetProcessStopCount () const { return m_pid_stop_count; }
+ bool SetProcessStopCount (nub_size_t count)
+ {
+ // Returns true if this class' notion of the PID state changed
+ if (m_pid_stop_count == count)
+ return false; // Didn't change
+ m_pid_stop_count = count;
+ return true; // The stop count has changed.
+ }
+
+ bool ProcessStateRunning() const;
+ PThreadEvent& Events( ) { return m_events; }
+ nub_event_t AllEventBits() const { return all_event_bits; }
+ nub_event_t NormalEventBits() const { return normal_event_bits; }
+ nub_event_t StickyEventBits() const { return sticky_event_bits; }
+ const char* EventsAsString (nub_event_t events, std::string& s);
+
+ int ArgumentCount () const { return m_arg_vec.size(); }
+ const char * ArgumentAtIndex (int index);
+ void PushArgument (const char *arg) { if (arg) m_arg_vec.push_back (arg); }
+ void ClearArgv () { m_arg_vec.erase (m_arg_vec.begin(), m_arg_vec.end()); }
+
+ int EnvironmentCount () const { return m_env_vec.size(); }
+ const char * EnvironmentAtIndex (int index);
+ void PushEnvironment (const char *arg) { if (arg) m_env_vec.push_back (arg); }
+ void ClearEnvironment () { m_env_vec.erase (m_env_vec.begin(), m_env_vec.end()); }
+ DNBError& LaunchStatus () { return m_launch_status; }
+ const char * LaunchStatusAsString (std::string& s);
+ nub_launch_flavor_t LaunchFlavor () const { return m_launch_flavor; }
+ void SetLaunchFlavor (nub_launch_flavor_t flavor) { m_launch_flavor = flavor; }
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from RNBContext can see and modify these
+ //------------------------------------------------------------------
+ nub_process_t m_pid;
+ nub_size_t m_pid_stop_count;
+ PThreadEvent m_events; // Threaded events that we can wait for
+ pthread_t m_pid_pthread;
+ nub_launch_flavor_t m_launch_flavor; // How to launch our inferior process
+ DNBError m_launch_status; // This holds the status from the last launch attempt.
+ std::vector<std::string> m_arg_vec;
+ std::vector<std::string> m_env_vec; // This will be unparsed - entries FOO=value
+
+ void StartProcessStatusThread();
+ void StopProcessStatusThread();
+ static void* ThreadFunctionProcessStatus(void *arg);
+
+private:
+ //------------------------------------------------------------------
+ // Outlaw copy and assignment operators
+ //------------------------------------------------------------------
+ RNBContext(const RNBContext& rhs);
+ RNBContext& operator=(const RNBContext& rhs);
+};
+
+#endif // #ifndef __RNBContext_h__
diff --git a/lldb/tools/debugserver/source/RNBDefs.h b/lldb/tools/debugserver/source/RNBDefs.h
new file mode 100644
index 00000000000..f603d3d22a6
--- /dev/null
+++ b/lldb/tools/debugserver/source/RNBDefs.h
@@ -0,0 +1,78 @@
+//===-- RNBDefs.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 12/14/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __RNBDefs_h__
+#define __RNBDefs_h__
+
+#include "DNBDefs.h"
+
+#include <tr1/memory> // for std::tr1::shared_ptr
+
+extern "C" const unsigned char debugserverVersionString[];
+extern "C" const double debugserverVersionNumber;
+#define DEBUGSERVER_PROGRAM_NAME "debugserver"
+#define DEBUGSERVER_VERSION_STR debugserverVersionString
+#define DEBUGSERVER_VERSION_NUM debugserverVersionNumber
+
+#if defined (__i386__)
+
+#define RNB_ARCH "i386"
+
+#elif defined (__x86_64__)
+
+#define RNB_ARCH "x86_64"
+
+#elif defined (__ppc64__)
+
+#define RNB_ARCH "ppc64"
+
+#elif defined (__powerpc__) || defined (__ppc__)
+
+#define RNB_ARCH "ppc"
+
+#elif defined (__arm__)
+
+#define RNB_ARCH "armv6"
+
+#else
+
+#error undefined architecture
+
+#endif
+
+class RNBRemote;
+typedef std::tr1::shared_ptr<RNBRemote> RNBRemoteSP;
+
+typedef enum
+{
+ rnb_success = 0,
+ rnb_err = 1,
+ rnb_not_connected = 2
+} rnb_err_t;
+
+// Log bits
+// reserve low bits for DNB
+#define LOG_RNB_MINIMAL ((LOG_LO_USER) << 0) // Minimal logging (min verbosity)
+#define LOG_RNB_MEDIUM ((LOG_LO_USER) << 1) // Medium logging (med verbosity)
+#define LOG_RNB_MAX ((LOG_LO_USER) << 2) // Max logging (max verbosity)
+#define LOG_RNB_COMM ((LOG_LO_USER) << 3) // Log communications (RNBSocket)
+#define LOG_RNB_REMOTE ((LOG_LO_USER) << 4) // Log remote (RNBRemote)
+#define LOG_RNB_EVENTS ((LOG_LO_USER) << 5) // Log events (PThreadEvents)
+#define LOG_RNB_PROC ((LOG_LO_USER) << 6) // Log process state (Process thread)
+#define LOG_RNB_PACKETS ((LOG_LO_USER) << 7) // Log gdb remote packets
+#define LOG_RNB_ALL (~((LOG_LO_USER) - 1))
+#define LOG_RNB_DEFAULT (LOG_RNB_ALL)
+
+extern RNBRemoteSP g_remoteSP;
+
+#endif // #ifndef __RNBDefs_h__
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
new file mode 100644
index 00000000000..3ac3ee9178f
--- /dev/null
+++ b/lldb/tools/debugserver/source/RNBRemote.cpp
@@ -0,0 +1,3187 @@
+//===-- RNBRemote.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 12/12/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RNBRemote.h"
+
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <mach/exception_types.h>
+#include <sys/sysctl.h>
+
+#include "DNB.h"
+#include "DNBLog.h"
+#include "DNBThreadResumeActions.h"
+#include "RNBContext.h"
+#include "RNBServices.h"
+#include "RNBSocket.h"
+#include "StringExtractor.h"
+
+#include <iomanip>
+#include <sstream>
+
+#include <TargetConditionals.h> // for endianness predefines
+
+//----------------------------------------------------------------------
+// std::iostream formatting macros
+//----------------------------------------------------------------------
+#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)((uint8_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 RAWHEX_SIZE(x, sz) RAW_HEXBASE << std::setw((sz)) << (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)) << ""
+// Class to handle communications via gdb remote protocol.
+
+extern void ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args);
+
+RNBRemote::RNBRemote (bool use_native_regs) :
+ m_ctx(),
+ m_comm(),
+ m_extended_mode(false),
+ m_noack_mode(false),
+ m_continue_thread(-1),
+ m_thread(-1),
+ m_mutex(),
+ m_packets_recvd(0),
+ m_packets(),
+ m_rx_packets(),
+ m_rx_partial_data(),
+ m_rx_pthread(0),
+ m_breakpoints(),
+ m_max_payload_size(DEFAULT_GDB_REMOTE_PROTOCOL_BUFSIZE - 4),
+ m_use_native_regs (use_native_regs)
+{
+ DNBLogThreadedIf (LOG_RNB_REMOTE, "%s", __PRETTY_FUNCTION__);
+ CreatePacketTable ();
+}
+
+
+RNBRemote::~RNBRemote()
+{
+ DNBLogThreadedIf (LOG_RNB_REMOTE, "%s", __PRETTY_FUNCTION__);
+ StopReadRemoteDataThread();
+}
+
+void
+RNBRemote::CreatePacketTable ()
+{
+ // Step required to add new packets:
+ // 1 - Add new enumeration to RNBRemote::PacketEnum
+ // 2 - Create a the RNBRemote::HandlePacket_ function if a new function is needed
+ // 3 - Register the Packet definition with any needed callbacks in this fucntion
+ // - If no response is needed for a command, then use NULL for the normal callback
+ // - If the packet is not supported while the target is running, use NULL for the async callback
+ // 4 - If the packet is a standard packet (starts with a '$' character
+ // followed by the payload and then '#' and checksum, then you are done
+ // else go on to step 5
+ // 5 - if the packet is a fixed length packet:
+ // - modify the switch statement for the first character in the payload
+ // in RNBRemote::CommDataReceived so it doesn't reject the new packet
+ // type as invalid
+ // - modify the switch statement for the first character in the payload
+ // in RNBRemote::GetPacketPayload and make sure the payload of the packet
+ // is returned correctly
+
+ std::vector <Packet> &t = m_packets;
+ t.push_back (Packet (ack, NULL, NULL, "+", "ACK"));
+ t.push_back (Packet (nack, NULL, NULL, "-", "!ACK"));
+ t.push_back (Packet (read_memory, &RNBRemote::HandlePacket_m, NULL, "m", "Read memory"));
+ t.push_back (Packet (read_register, &RNBRemote::HandlePacket_p, NULL, "p", "Read one register"));
+ t.push_back (Packet (read_general_regs, &RNBRemote::HandlePacket_g, NULL, "g", "Read registers"));
+ t.push_back (Packet (write_memory, &RNBRemote::HandlePacket_M, NULL, "M", "Write memory"));
+ t.push_back (Packet (write_register, &RNBRemote::HandlePacket_P, NULL, "P", "Write one register"));
+ t.push_back (Packet (write_general_regs, &RNBRemote::HandlePacket_G, NULL, "G", "Write registers"));
+ t.push_back (Packet (insert_mem_bp, &RNBRemote::HandlePacket_z, NULL, "Z0", "Insert memory breakpoint"));
+ t.push_back (Packet (remove_mem_bp, &RNBRemote::HandlePacket_z, NULL, "z0", "Remove memory breakpoint"));
+ t.push_back (Packet (single_step, &RNBRemote::HandlePacket_s, NULL, "s", "Single step"));
+ t.push_back (Packet (cont, &RNBRemote::HandlePacket_c, NULL, "c", "continue"));
+ t.push_back (Packet (single_step_with_sig, &RNBRemote::HandlePacket_S, NULL, "S", "Single step with signal"));
+ t.push_back (Packet (set_thread, &RNBRemote::HandlePacket_H, NULL, "H", "Set thread"));
+ t.push_back (Packet (halt, &RNBRemote::HandlePacket_last_signal, &RNBRemote::HandlePacket_stop_process, "\x03", "^C"));
+// t.push_back (Packet (use_extended_mode, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "!", "Use extended mode"));
+ t.push_back (Packet (why_halted, &RNBRemote::HandlePacket_last_signal, NULL, "?", "Why did target halt"));
+ t.push_back (Packet (set_argv, &RNBRemote::HandlePacket_A, NULL, "A", "Set argv"));
+// t.push_back (Packet (set_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "B", "Set/clear breakpoint"));
+ t.push_back (Packet (continue_with_sig, &RNBRemote::HandlePacket_C, NULL, "C", "Continue with signal"));
+ t.push_back (Packet (detach, &RNBRemote::HandlePacket_D, NULL, "D", "Detach gdb from remote system"));
+// t.push_back (Packet (step_inferior_one_cycle, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "i", "Step inferior by one clock cycle"));
+// t.push_back (Packet (signal_and_step_inf_one_cycle, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "I", "Signal inferior, then step one clock cyle"));
+ t.push_back (Packet (kill, &RNBRemote::HandlePacket_k, NULL, "k", "Kill"));
+// t.push_back (Packet (restart, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "R", "Restart inferior"));
+// t.push_back (Packet (search_mem_backwards, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "t", "Search memory backwards"));
+ t.push_back (Packet (thread_alive_p, &RNBRemote::HandlePacket_T, NULL, "T", "Is thread alive"));
+ t.push_back (Packet (vattach, &RNBRemote::HandlePacket_v, NULL, "vAttach", "Attach to a new process"));
+ t.push_back (Packet (vattachwait, &RNBRemote::HandlePacket_v, NULL, "vAttachWait", "Wait for a process to start up then attach to it"));
+ t.push_back (Packet (vcont_list_actions, &RNBRemote::HandlePacket_v, NULL, "vCont;", "Verbose resume with thread actions"));
+ t.push_back (Packet (vcont_list_actions, &RNBRemote::HandlePacket_v, NULL, "vCont?", "List valid continue-with-thread-actions actions"));
+ // The X packet doesn't currently work. If/when it does, remove the line above and uncomment out the line below
+// t.push_back (Packet (write_data_to_memory, &RNBRemote::HandlePacket_X, NULL, "X", "Write data to memory"));
+// t.push_back (Packet (insert_hardware_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "Z1", "Insert hardware breakpoint"));
+// t.push_back (Packet (remove_hardware_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "z1", "Remove hardware breakpoint"));
+// t.push_back (Packet (insert_write_watch_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "Z2", "Insert write watchpoint"));
+// t.push_back (Packet (remove_write_watch_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "z2", "Remove write watchpoint"));
+// t.push_back (Packet (insert_read_watch_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "Z3", "Insert read watchpoint"));
+// t.push_back (Packet (remove_read_watch_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "z3", "Remove read watchpoint"));
+// t.push_back (Packet (insert_access_watch_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "Z4", "Insert access watchpoint"));
+// t.push_back (Packet (remove_access_watch_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "z4", "Remove access watchpoint"));
+ t.push_back (Packet (query_current_thread_id, &RNBRemote::HandlePacket_qC, NULL, "qC", "Query current thread ID"));
+// t.push_back (Packet (query_memory_crc, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "qCRC:", "Compute CRC of memory region"));
+ t.push_back (Packet (query_thread_ids_first, &RNBRemote::HandlePacket_qThreadInfo, NULL, "qfThreadInfo", "Get list of active threads (first req)"));
+ t.push_back (Packet (query_thread_ids_subsequent, &RNBRemote::HandlePacket_qThreadInfo, NULL, "qsThreadInfo", "Get list of active threads (subsequent req)"));
+ // APPLE LOCAL: qThreadStopInfo
+ // syntax: qThreadStopInfoTTTT
+ // TTTT is hex thread ID
+ t.push_back (Packet (query_thread_stop_info, &RNBRemote::HandlePacket_qThreadStopInfo, NULL, "qThreadStopInfo", "Get detailed info on why the specified thread stopped"));
+ t.push_back (Packet (query_thread_extra_info, &RNBRemote::HandlePacket_qThreadExtraInfo,NULL, "qThreadExtraInfo", "Get printable status of a thread"));
+// t.push_back (Packet (query_image_offsets, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "qOffsets", "Report offset of loaded program"));
+ t.push_back (Packet (query_launch_success, &RNBRemote::HandlePacket_qLaunchSuccess,NULL, "qLaunchSuccess", "Report the success or failure of the launch attempt"));
+ t.push_back (Packet (query_register_info, &RNBRemote::HandlePacket_qRegisterInfo, NULL, "qRegisterInfo", "Dynamically discover remote register context information."));
+ t.push_back (Packet (query_shlib_notify_info_addr, &RNBRemote::HandlePacket_qShlibInfoAddr,NULL, "qShlibInfoAddr", "Returns the address that contains info needed for getting shared library notifications"));
+ t.push_back (Packet (query_step_packet_supported, &RNBRemote::HandlePacket_qStepPacketSupported,NULL, "qStepPacketSupported", "Replys with OK if the 's' packet is supported."));
+ t.push_back (Packet (query_host_info, &RNBRemote::HandlePacket_qHostInfo, NULL, "qHostInfo", "Replies with multiple 'key:value;' tuples appended to each other."));
+// t.push_back (Packet (query_symbol_lookup, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "qSymbol", "Notify that host debugger is ready to do symbol lookups"));
+ t.push_back (Packet (start_noack_mode, &RNBRemote::HandlePacket_Q , NULL, "QStartNoAckMode", "Request that " DEBUGSERVER_PROGRAM_NAME " stop acking remote protocol packets"));
+ t.push_back (Packet (set_logging_mode, &RNBRemote::HandlePacket_Q , NULL, "QSetLogging:", "Request that the " DEBUGSERVER_PROGRAM_NAME " set its logging mode bits"));
+ t.push_back (Packet (set_max_packet_size, &RNBRemote::HandlePacket_Q , NULL, "QSetMaxPacketSize:", "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized packet gdb can handle"));
+ t.push_back (Packet (set_max_payload_size, &RNBRemote::HandlePacket_Q , NULL, "QSetMaxPayloadSize:", "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized payload gdb can handle"));
+ t.push_back (Packet (set_environment_variable, &RNBRemote::HandlePacket_Q , NULL, "QEnvironment:", "Add an environment variable to the inferior's environment"));
+// t.push_back (Packet (pass_signals_to_inferior, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "QPassSignals:", "Specify which signals are passed to the inferior"));
+ t.push_back (Packet (allocate_memory, &RNBRemote::HandlePacket_AllocateMemory, NULL, "_M", "Allocate memory in the inferior process."));
+ t.push_back (Packet (deallocate_memory, &RNBRemote::HandlePacket_DeallocateMemory, NULL, "_m", "Deallocate memory in the inferior process."));
+}
+
+
+void
+RNBRemote::FlushSTDIO ()
+{
+ if (m_ctx.HasValidProcessID())
+ {
+ nub_process_t pid = m_ctx.ProcessID();
+ char buf[256];
+ nub_size_t count;
+ do
+ {
+ count = DNBProcessGetAvailableSTDOUT(pid, buf, sizeof(buf));
+ if (count > 0)
+ {
+ SendSTDOUTPacket (buf, count);
+ }
+ } while (count > 0);
+
+ do
+ {
+ count = DNBProcessGetAvailableSTDERR(pid, buf, sizeof(buf));
+ if (count > 0)
+ {
+ SendSTDERRPacket (buf, count);
+ }
+ } while (count > 0);
+ }
+}
+
+rnb_err_t
+RNBRemote::SendHexEncodedBytePacket (const char *header, const void *buf, size_t buf_len, const char *footer)
+{
+ std::ostringstream packet_sstrm;
+ // Append the header cstr if there was one
+ if (header && header[0])
+ packet_sstrm << header;
+ nub_size_t i;
+ const uint8_t *ubuf8 = (const uint8_t *)buf;
+ for (i=0; i<buf_len; i++)
+ {
+ packet_sstrm << RAWHEX8(ubuf8[i]);
+ }
+ // Append the footer cstr if there was one
+ if (footer && footer[0])
+ packet_sstrm << footer;
+
+ return SendPacket(packet_sstrm.str());
+}
+
+rnb_err_t
+RNBRemote::SendSTDOUTPacket (char *buf, nub_size_t buf_size)
+{
+ if (buf_size == 0)
+ return rnb_success;
+ return SendHexEncodedBytePacket("O", buf, buf_size, NULL);
+}
+
+rnb_err_t
+RNBRemote::SendSTDERRPacket (char *buf, nub_size_t buf_size)
+{
+ if (buf_size == 0)
+ return rnb_success;
+ return SendHexEncodedBytePacket("O", buf, buf_size, NULL);
+}
+
+rnb_err_t
+RNBRemote::SendPacket (const std::string &s)
+{
+ DNBLogThreadedIf (LOG_RNB_MAX, "%8d RNBRemote::%s (%s) called", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, s.c_str());
+ std::string sendpacket = "$" + s + "#";
+ int cksum = 0;
+ char hexbuf[5];
+
+ if (m_noack_mode)
+ {
+ sendpacket += "00";
+ }
+ else
+ {
+ for (int i = 0; i != s.size(); ++i)
+ cksum += s[i];
+ snprintf (hexbuf, sizeof hexbuf, "%02x", cksum & 0xff);
+ sendpacket += hexbuf;
+ }
+
+ rnb_err_t err = m_comm.Write (sendpacket.c_str(), sendpacket.size());
+ if (err != rnb_success)
+ return err;
+
+ if (m_noack_mode)
+ return rnb_success;
+
+ std::string reply;
+ RNBRemote::Packet packet;
+ err = GetPacket (reply, packet, true);
+
+ if (err != rnb_success)
+ {
+ DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s (%s) got error trying to get reply...", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, sendpacket.c_str());
+ return err;
+ }
+
+ DNBLogThreadedIf (LOG_RNB_MAX, "%8d RNBRemote::%s (%s) got reply: '%s'", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, sendpacket.c_str(), reply.c_str());
+
+ if (packet.type == ack)
+ return rnb_success;
+
+ // Should we try to resend the packet at this layer?
+ // if (packet.command == nack)
+ return rnb_err;
+}
+
+/* Get a packet via gdb remote protocol.
+ Strip off the prefix/suffix, verify the checksum to make sure
+ a valid packet was received, send an ACK if they match. */
+
+rnb_err_t
+RNBRemote::GetPacketPayload (std::string &return_packet)
+{
+ //DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s called", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);
+
+ PThreadMutex::Locker locker(m_mutex);
+ if (m_rx_packets.empty())
+ {
+ // Only reset the remote command available event if we have no more packets
+ m_ctx.Events().ResetEvents ( RNBContext::event_read_packet_available );
+ //DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s error: no packets available...", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);
+ return rnb_err;
+ }
+
+ //DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s has %u queued packets", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, m_rx_packets.size());
+ return_packet.swap(m_rx_packets.front());
+ m_rx_packets.pop_front();
+ locker.Reset(); // Release our lock on the mutex
+
+ if (m_rx_packets.empty())
+ {
+ // Reset the remote command available event if we have no more packets
+ m_ctx.Events().ResetEvents ( RNBContext::event_read_packet_available );
+ }
+
+ //DNBLogThreadedIf (LOG_RNB_MEDIUM, "%8u RNBRemote::%s: '%s'", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, return_packet.c_str());
+
+ switch (return_packet[0])
+ {
+ case '+':
+ case '-':
+ case '\x03':
+ break;
+
+ case '$':
+ {
+ int packet_checksum = 0;
+ if (!m_noack_mode)
+ {
+ for (int i = return_packet.size() - 2; i < return_packet.size(); ++i)
+ {
+ char checksum_char = tolower (return_packet[i]);
+ if (!isxdigit (checksum_char))
+ {
+ m_comm.Write ("-", 1);
+ DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s error: packet with invalid checksum characters: %s", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, return_packet.c_str());
+ return rnb_err;
+ }
+ }
+ packet_checksum = strtol (&return_packet[return_packet.size() - 2], NULL, 16);
+ }
+
+ return_packet.erase(0,1); // Strip the leading '$'
+ return_packet.erase(return_packet.size() - 3);// Strip the #XX checksum
+
+ if (!m_noack_mode)
+ {
+ // Compute the checksum
+ int computed_checksum = 0;
+ for (std::string::iterator it = return_packet.begin ();
+ it != return_packet.end ();
+ ++it)
+ {
+ computed_checksum += *it;
+ }
+
+ if (packet_checksum == (computed_checksum & 0xff))
+ {
+ //DNBLogThreadedIf (LOG_RNB_MEDIUM, "%8u RNBRemote::%s sending ACK for '%s'", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, return_packet.c_str());
+ m_comm.Write ("+", 1);
+ }
+ else
+ {
+ DNBLogThreadedIf (LOG_RNB_MEDIUM, "%8u RNBRemote::%s sending ACK for '%s' (error: packet checksum mismatch (0x%2.2x != 0x%2.2x))",
+ (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),
+ __FUNCTION__,
+ return_packet.c_str(),
+ packet_checksum,
+ computed_checksum);
+ m_comm.Write ("-", 1);
+ return rnb_err;
+ }
+ }
+ }
+ break;
+
+ default:
+ DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s tossing unexpected packet???? %s", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, return_packet.c_str());
+ if (!m_noack_mode)
+ m_comm.Write ("-", 1);
+ return rnb_err;
+ }
+
+ return rnb_success;
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_UNIMPLEMENTED (const char* p)
+{
+ DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s(\"%s\")", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, p ? p : "NULL");
+ return SendPacket ("");
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_ILLFORMED (const char *description)
+{
+ DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s sending ILLFORMED", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);
+ return SendPacket ("E03");
+}
+
+rnb_err_t
+RNBRemote::GetPacket (std::string &packet_payload, RNBRemote::Packet& packet_info, bool wait)
+{
+ std::string payload;
+ rnb_err_t err = GetPacketPayload (payload);
+ if (err != rnb_success)
+ {
+ PThreadEvent& events = m_ctx.Events();
+ nub_event_t set_events = events.GetEventBits();
+ // TODO: add timeout version of GetPacket?? We would then need to pass
+ // that timeout value along to DNBProcessTimedWaitForEvent.
+ if (!wait || ((set_events & RNBContext::event_read_thread_running) == 0))
+ return err;
+
+ const nub_event_t events_to_wait_for = RNBContext::event_read_packet_available | RNBContext::event_read_thread_exiting;
+ set_events = 0;
+
+ while ((set_events = events.WaitForSetEvents(events_to_wait_for)) != 0)
+ {
+ if (set_events & RNBContext::event_read_packet_available)
+ {
+ // Try the queue again now that we got an event
+ err = GetPacketPayload (payload);
+ if (err == rnb_success)
+ break;
+ }
+
+ if (set_events & RNBContext::event_read_thread_exiting)
+ err = rnb_not_connected;
+
+ if (err == rnb_not_connected)
+ return err;
+
+ } while (err == rnb_err);
+
+ if (set_events == 0)
+ err = rnb_not_connected;
+ }
+
+ if (err == rnb_success)
+ {
+ Packet::iterator it;
+ for (it = m_packets.begin (); it != m_packets.end (); ++it)
+ {
+ if (payload.compare (0, it->abbrev.size(), it->abbrev) == 0)
+ break;
+ }
+
+ // A packet we don't have an entry for. This can happen when we
+ // get a packet that we don't know about or support. We just reply
+ // accordingly and go on.
+ if (it == m_packets.end ())
+ {
+ DNBLogThreadedIf (LOG_RNB_PACKETS, "unimplemented packet: '%s'", payload.c_str());
+ HandlePacket_UNIMPLEMENTED(payload.c_str());
+ return rnb_err;
+ }
+ else
+ {
+ packet_info = *it;
+ packet_payload = payload;
+ }
+ }
+ return err;
+}
+
+rnb_err_t
+RNBRemote::HandleAsyncPacket(PacketEnum *type)
+{
+ DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);
+ static DNBTimer g_packetTimer(true);
+ rnb_err_t err = rnb_err;
+ std::string packet_data;
+ RNBRemote::Packet packet_info;
+ err = GetPacket (packet_data, packet_info, false);
+
+ if (err == rnb_success)
+ {
+ if (!packet_data.empty() && isprint(packet_data[0]))
+ DNBLogThreadedIf (LOG_RNB_REMOTE | LOG_RNB_PACKETS, "HandleAsyncPacket (\"%s\");", packet_data.c_str());
+ else
+ DNBLogThreadedIf (LOG_RNB_REMOTE | LOG_RNB_PACKETS, "HandleAsyncPacket (%s);", packet_info.printable_name.c_str());
+
+ HandlePacketCallback packet_callback = packet_info.async;
+ if (packet_callback != NULL)
+ {
+ if (type != NULL)
+ *type = packet_info.type;
+ return (this->*packet_callback)(packet_data.c_str());
+ }
+ }
+
+ return err;
+}
+
+rnb_err_t
+RNBRemote::HandleReceivedPacket(PacketEnum *type)
+{
+ static DNBTimer g_packetTimer(true);
+
+ // DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);
+ rnb_err_t err = rnb_err;
+ std::string packet_data;
+ RNBRemote::Packet packet_info;
+ err = GetPacket (packet_data, packet_info, false);
+
+ if (err == rnb_success)
+ {
+ DNBLogThreadedIf (LOG_RNB_REMOTE, "HandleReceivedPacket (\"%s\");", packet_data.c_str());
+ HandlePacketCallback packet_callback = packet_info.normal;
+ if (packet_callback != NULL)
+ {
+ if (type != NULL)
+ *type = packet_info.type;
+ return (this->*packet_callback)(packet_data.c_str());
+ }
+ else
+ {
+ // Do not fall through to end of this function, if we have valid
+ // packet_info and it has a NULL callback, then we need to respect
+ // that it may not want any response or anything to be done.
+ return err;
+ }
+ }
+ return rnb_err;
+}
+
+void
+RNBRemote::CommDataReceived(const std::string& new_data)
+{
+ // DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s called", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);
+ {
+ // Put the packet data into the buffer in a thread safe fashion
+ PThreadMutex::Locker locker(m_mutex);
+
+ std::string data;
+ // See if we have any left over data from a previous call to this
+ // function?
+ if (!m_rx_partial_data.empty())
+ {
+ // We do, so lets start with that data
+ data.swap(m_rx_partial_data);
+ }
+ // Append the new incoming data
+ data += new_data;
+
+ // Parse up the packets into gdb remote packets
+ uint32_t idx = 0;
+ const size_t data_size = data.size();
+
+ while (idx < data_size)
+ {
+ // 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 end_idx = idx;
+
+ switch (data[idx])
+ {
+ case '+': // Look for ack
+ case '-': // Look for cancel
+ case '\x03': // ^C to halt target
+ end_idx = idx + 1; // The command is one byte long...
+ break;
+
+ case '$':
+ // Look for a standard gdb packet?
+ end_idx = data.find('#', idx + 1);
+ if (end_idx == std::string::npos || end_idx + 2 > data_size)
+ {
+ end_idx = std::string::npos;
+ }
+ else
+ {
+ // Add two for the checksum bytes
+ end_idx += 4;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (end_idx == std::string::npos)
+ {
+ // Not all data may be here for the packet yet, save it for
+ // next time through this function.
+ m_rx_partial_data += data.substr(idx);
+ //DNBLogThreadedIf (LOG_RNB_MAX, "%8d RNBRemote::%s saving data for later[%u, npos): '%s'",(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, idx, m_rx_partial_data.c_str());
+ idx = end_idx;
+ }
+ else
+ if (idx < end_idx)
+ {
+ m_packets_recvd++;
+ // Hack to get rid of initial '+' ACK???
+ if (m_packets_recvd == 1 && (end_idx == idx + 1) && data[idx] == '+')
+ {
+ //DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s throwing first ACK away....[%u, npos): '+'",(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, idx);
+ }
+ else
+ {
+ // We have a valid packet...
+ m_rx_packets.push_back(data.substr(idx, end_idx - idx));
+ DNBLogThreadedIf (LOG_RNB_PACKETS, "getpkt: %s", m_rx_packets.back().c_str());
+ }
+ idx = end_idx;
+ }
+ else
+ {
+ DNBLogThreadedIf (LOG_RNB_MAX, "%8d RNBRemote::%s tossing junk byte at %c",(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, data[idx]);
+ idx = idx + 1;
+ }
+ }
+ }
+
+ if (!m_rx_packets.empty())
+ {
+ // Let the main thread know we have received a packet
+
+ //DNBLogThreadedIf (LOG_RNB_EVENTS, "%8d RNBRemote::%s called events.SetEvent(RNBContext::event_read_packet_available)", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);
+ PThreadEvent& events = m_ctx.Events();
+ events.SetEvents (RNBContext::event_read_packet_available);
+ }
+}
+
+rnb_err_t
+RNBRemote::GetCommData ()
+{
+ // DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s called", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);
+ std::string comm_data;
+ rnb_err_t err = m_comm.Read (comm_data);
+ if (err == rnb_success)
+ {
+ if (!comm_data.empty())
+ CommDataReceived (comm_data);
+ }
+ return err;
+}
+
+void
+RNBRemote::StartReadRemoteDataThread()
+{
+ DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s called", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);
+ PThreadEvent& events = m_ctx.Events();
+ if ((events.GetEventBits() & RNBContext::event_read_thread_running) == 0)
+ {
+ events.ResetEvents (RNBContext::event_read_thread_exiting);
+ int err = ::pthread_create (&m_rx_pthread, NULL, ThreadFunctionReadRemoteData, this);
+ if (err == 0)
+ {
+ // Our thread was successfully kicked off, wait for it to
+ // set the started event so we can safely continue
+ events.WaitForSetEvents (RNBContext::event_read_thread_running);
+ }
+ else
+ {
+ events.ResetEvents (RNBContext::event_read_thread_running);
+ events.SetEvents (RNBContext::event_read_thread_exiting);
+ }
+ }
+}
+
+void
+RNBRemote::StopReadRemoteDataThread()
+{
+ DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s called", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);
+ PThreadEvent& events = m_ctx.Events();
+ if ((events.GetEventBits() & RNBContext::event_read_thread_running) == RNBContext::event_read_thread_running)
+ {
+ m_comm.Disconnect(true);
+ struct timespec timeout_abstime;
+ DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0);
+
+ // Wait for 2 seconds for the remote data thread to exit
+ if (events.WaitForSetEvents(RNBContext::event_read_thread_exiting, &timeout_abstime) == 0)
+ {
+ // Kill the remote data thread???
+ }
+ }
+}
+
+
+void*
+RNBRemote::ThreadFunctionReadRemoteData(void *arg)
+{
+ // Keep a shared pointer reference so this doesn't go away on us before the thread is killed.
+ DNBLogThreadedIf(LOG_RNB_REMOTE, "RNBRemote::%s (%p): thread starting...", __FUNCTION__, arg);
+ RNBRemoteSP remoteSP(g_remoteSP);
+ if (remoteSP.get() != NULL)
+ {
+ RNBRemote* remote = remoteSP.get();
+ PThreadEvent& events = remote->Context().Events();
+ events.SetEvents (RNBContext::event_read_thread_running);
+ // START: main receive remote command thread loop
+ bool done = false;
+ while (!done)
+ {
+ rnb_err_t err = remote->GetCommData();
+
+ switch (err)
+ {
+ case rnb_success:
+ break;
+
+ default:
+ case rnb_err:
+ DNBLogThreadedIf (LOG_RNB_REMOTE, "RNBSocket::GetCommData returned error %u", err);
+ done = true;
+ break;
+
+ case rnb_not_connected:
+ DNBLogThreadedIf (LOG_RNB_REMOTE, "RNBSocket::GetCommData returned not connected...");
+ done = true;
+ break;
+ }
+ }
+ // START: main receive remote command thread loop
+ events.ResetEvents (RNBContext::event_read_thread_running);
+ events.SetEvents (RNBContext::event_read_thread_exiting);
+ }
+ DNBLogThreadedIf(LOG_RNB_REMOTE, "RNBRemote::%s (%p): thread exiting...", __FUNCTION__, arg);
+ return NULL;
+}
+
+
+
+/* Read the bytes in STR which are GDB Remote Protocol binary encoded bytes
+ (8-bit bytes).
+ This encoding uses 0x7d ('}') as an escape character for 0x7d ('}'),
+ 0x23 ('#'), and 0x24 ('$').
+ LEN is the number of bytes to be processed. If a character is escaped,
+ it is 2 characters for LEN. A LEN of -1 means encode-until-nul-byte
+ (end of string). */
+
+std::vector<uint8_t>
+decode_binary_data (const char *str, int len)
+{
+ std::vector<uint8_t> bytes;
+ if (len == 0)
+ {
+ return bytes;
+ }
+ if (len == -1)
+ len = strlen (str);
+
+ while (len--)
+ {
+ unsigned char c = *str;
+ if (c == 0x7d && len > 0)
+ {
+ len--;
+ str++;
+ c ^= 0x20;
+ }
+ bytes.push_back (c);
+ }
+ return bytes;
+}
+
+typedef struct register_map_entry
+{
+ uint32_t gdb_regnum; // gdb register number
+ uint32_t gdb_size; // gdb register size in bytes (can be greater than or less than to debugnub size...)
+ const char * gdb_name; // gdb register name
+ DNBRegisterInfo nub_info; // debugnub register info
+ const uint8_t* fail_value; // Value to print if case we fail to reg this register (if this is NULL, we will return an error)
+ int expedite; // expedite delivery of this register in last stop reply packets
+} register_map_entry_t;
+
+
+
+// If the notion of registers differs from what is handed out by the
+// architecture, then flavors can be defined here.
+
+static const uint32_t MAX_REGISTER_BYTE_SIZE = 16;
+static const uint8_t k_zero_bytes[MAX_REGISTER_BYTE_SIZE] = {0};
+static std::vector<register_map_entry_t> g_dynamic_register_map;
+static register_map_entry_t *g_reg_entries = NULL;
+static size_t g_num_reg_entries = 0;
+
+static void
+RegisterEntryNotAvailable (register_map_entry_t *reg_entry)
+{
+ reg_entry->fail_value = k_zero_bytes;
+ reg_entry->nub_info.set = INVALID_NUB_REGNUM;
+ reg_entry->nub_info.reg = INVALID_NUB_REGNUM;
+ reg_entry->nub_info.name = NULL;
+ reg_entry->nub_info.alt = NULL;
+ reg_entry->nub_info.type = InvalidRegType;
+ reg_entry->nub_info.format = InvalidRegFormat;
+ reg_entry->nub_info.size = 0;
+ reg_entry->nub_info.offset = 0;
+ reg_entry->nub_info.reg_gcc = INVALID_NUB_REGNUM;
+ reg_entry->nub_info.reg_dwarf = INVALID_NUB_REGNUM;
+ reg_entry->nub_info.reg_generic = INVALID_NUB_REGNUM;
+ reg_entry->nub_info.reg_gdb = INVALID_NUB_REGNUM;
+}
+
+#if defined (__arm__)
+
+//----------------------------------------------------------------------
+// ARM regiseter sets as gdb knows them
+//----------------------------------------------------------------------
+
+register_map_entry_t
+g_gdb_register_map_arm[] =
+{
+ { 0, 4, "r0", {0}, NULL, 1},
+ { 1, 4, "r1", {0}, NULL, 1},
+ { 2, 4, "r2", {0}, NULL, 1},
+ { 3, 4, "r3", {0}, NULL, 1},
+ { 4, 4, "r4", {0}, NULL, 1},
+ { 5, 4, "r5", {0}, NULL, 1},
+ { 6, 4, "r6", {0}, NULL, 1},
+ { 7, 4, "r7", {0}, NULL, 1},
+ { 8, 4, "r8", {0}, NULL, 1},
+ { 9, 4, "r9", {0}, NULL, 1},
+ { 10, 4, "r10", {0}, NULL, 1},
+ { 11, 4, "r11", {0}, NULL, 1},
+ { 12, 4, "r12", {0}, NULL, 1},
+ { 13, 4, "sp", {0}, NULL, 1},
+ { 14, 4, "lr", {0}, NULL, 1},
+ { 15, 4, "pc", {0}, NULL, 1},
+ { 16, 12, "f0", NULL, k_zero_bytes, 0},
+ { 17, 12, "f1", NULL, k_zero_bytes, 0},
+ { 18, 12, "f2", NULL, k_zero_bytes, 0},
+ { 19, 12, "f3", NULL, k_zero_bytes, 0},
+ { 20, 12, "f4", NULL, k_zero_bytes, 0},
+ { 21, 12, "f5", NULL, k_zero_bytes, 0},
+ { 22, 12, "f6", NULL, k_zero_bytes, 0},
+ { 23, 12, "f7", NULL, k_zero_bytes, 0},
+ { 24, 4, "fps", {0}, NULL, 0},
+ { 25, 4,"cpsr", {0}, NULL, 1},
+ { 26, 4, "s0", {0}, NULL, 0},
+ { 27, 4, "s1", {0}, NULL, 0},
+ { 28, 4, "s2", {0}, NULL, 0},
+ { 29, 4, "s3", {0}, NULL, 0},
+ { 30, 4, "s4", {0}, NULL, 0},
+ { 31, 4, "s5", {0}, NULL, 0},
+ { 32, 4, "s6", {0}, NULL, 0},
+ { 33, 4, "s7", {0}, NULL, 0},
+ { 34, 4, "s8", {0}, NULL, 0},
+ { 35, 4, "s9", {0}, NULL, 0},
+ { 36, 4, "s10", {0}, NULL, 0},
+ { 37, 4, "s11", {0}, NULL, 0},
+ { 38, 4, "s12", {0}, NULL, 0},
+ { 39, 4, "s13", {0}, NULL, 0},
+ { 40, 4, "s14", {0}, NULL, 0},
+ { 41, 4, "s15", {0}, NULL, 0},
+ { 42, 4, "s16", {0}, NULL, 0},
+ { 43, 4, "s17", {0}, NULL, 0},
+ { 44, 4, "s18", {0}, NULL, 0},
+ { 45, 4, "s19", {0}, NULL, 0},
+ { 46, 4, "s20", {0}, NULL, 0},
+ { 47, 4, "s21", {0}, NULL, 0},
+ { 48, 4, "s22", {0}, NULL, 0},
+ { 49, 4, "s23", {0}, NULL, 0},
+ { 50, 4, "s24", {0}, NULL, 0},
+ { 51, 4, "s25", {0}, NULL, 0},
+ { 52, 4, "s26", {0}, NULL, 0},
+ { 53, 4, "s27", {0}, NULL, 0},
+ { 54, 4, "s28", {0}, NULL, 0},
+ { 55, 4, "s29", {0}, NULL, 0},
+ { 56, 4, "s30", {0}, NULL, 0},
+ { 57, 4, "s31", {0}, NULL, 0},
+ { 58, 4, "fpscr", {0}, NULL, 0}
+};
+
+void
+RNBRemote::InitializeRegisters (int use_native_registers)
+{
+ if (use_native_registers)
+ {
+ RNBRemote::InitializeNativeRegisters();
+ }
+ else
+ {
+ const size_t num_regs = sizeof (g_gdb_register_map_arm) / sizeof (register_map_entry_t);
+ for (uint32_t i=0; i<num_regs; ++i)
+ {
+ if (!DNBGetRegisterInfoByName (g_gdb_register_map_arm[i].gdb_name, &g_gdb_register_map_arm[i].nub_info))
+ {
+ RegisterEntryNotAvailable (&g_gdb_register_map_arm[i]);
+ assert (g_gdb_register_map_arm[i].gdb_size <= MAX_REGISTER_BYTE_SIZE);
+ }
+ }
+ g_reg_entries = g_gdb_register_map_arm;
+ g_num_reg_entries = sizeof (g_gdb_register_map_arm) / sizeof (register_map_entry_t);
+ }
+}
+
+
+#elif defined (__i386__)
+
+register_map_entry_t
+g_gdb_register_map_i386[] =
+{
+ { 0, 4, "eax" , {0}, NULL, 0 },
+ { 1, 4, "ecx" , {0}, NULL, 0 },
+ { 2, 4, "edx" , {0}, NULL, 0 },
+ { 3, 4, "ebx" , {0}, NULL, 0 },
+ { 4, 4, "esp" , {0}, NULL, 1 },
+ { 5, 4, "ebp" , {0}, NULL, 1 },
+ { 6, 4, "esi" , {0}, NULL, 0 },
+ { 7, 4, "edi" , {0}, NULL, 0 },
+ { 8, 4, "eip" , {0}, NULL, 1 },
+ { 9, 4, "eflags" , {0}, NULL, 0 },
+ { 10, 4, "cs" , {0}, NULL, 0 },
+ { 11, 4, "ss" , {0}, NULL, 0 },
+ { 12, 4, "ds" , {0}, NULL, 0 },
+ { 13, 4, "es" , {0}, NULL, 0 },
+ { 14, 4, "fs" , {0}, NULL, 0 },
+ { 15, 4, "gs" , {0}, NULL, 0 },
+ { 16, 10, "stmm0" , {0}, NULL, 0 },
+ { 17, 10, "stmm1" , {0}, NULL, 0 },
+ { 18, 10, "stmm2" , {0}, NULL, 0 },
+ { 19, 10, "stmm3" , {0}, NULL, 0 },
+ { 20, 10, "stmm4" , {0}, NULL, 0 },
+ { 21, 10, "stmm5" , {0}, NULL, 0 },
+ { 22, 10, "stmm6" , {0}, NULL, 0 },
+ { 23, 10, "stmm7" , {0}, NULL, 0 },
+ { 24, 4, "fctrl" , {0}, NULL, 0 },
+ { 25, 4, "fstat" , {0}, NULL, 0 },
+ { 26, 4, "ftag" , {0}, NULL, 0 },
+ { 27, 4, "fiseg" , {0}, NULL, 0 },
+ { 28, 4, "fioff" , {0}, NULL, 0 },
+ { 29, 4, "foseg" , {0}, NULL, 0 },
+ { 30, 4, "fooff" , {0}, NULL, 0 },
+ { 31, 4, "fop" , {0}, NULL, 0 },
+ { 32, 16, "xmm0" , {0}, NULL, 0 },
+ { 33, 16, "xmm1" , {0}, NULL, 0 },
+ { 34, 16, "xmm2" , {0}, NULL, 0 },
+ { 35, 16, "xmm3" , {0}, NULL, 0 },
+ { 36, 16, "xmm4" , {0}, NULL, 0 },
+ { 37, 16, "xmm5" , {0}, NULL, 0 },
+ { 38, 16, "xmm6" , {0}, NULL, 0 },
+ { 39, 16, "xmm7" , {0}, NULL, 0 },
+ { 40, 4, "mxcsr" , {0}, NULL, 0 },
+};
+
+void
+RNBRemote::InitializeRegisters (int use_native_registers)
+{
+ if (use_native_registers)
+ {
+ RNBRemote::InitializeNativeRegisters();
+ }
+ else
+ {
+ const size_t num_regs = sizeof (g_gdb_register_map_i386) / sizeof (register_map_entry_t);
+ for (uint32_t i=0; i<num_regs; ++i)
+ {
+ if (!DNBGetRegisterInfoByName (g_gdb_register_map_i386[i].gdb_name, &g_gdb_register_map_i386[i].nub_info))
+ {
+ RegisterEntryNotAvailable (&g_gdb_register_map_i386[i]);
+ assert (g_gdb_register_map_i386[i].gdb_size <= MAX_REGISTER_BYTE_SIZE);
+ }
+ }
+ g_reg_entries = g_gdb_register_map_i386;
+ g_num_reg_entries = sizeof (g_gdb_register_map_i386) / sizeof (register_map_entry_t);
+ }
+}
+
+
+#elif defined (__x86_64__)
+
+register_map_entry_t
+g_gdb_register_map_x86_64[] =
+{
+ { 0, 8, "rax" , {0}, NULL, 0 },
+ { 1, 8, "rbx" , {0}, NULL, 0 },
+ { 2, 8, "rcx" , {0}, NULL, 0 },
+ { 3, 8, "rdx" , {0}, NULL, 0 },
+ { 4, 8, "rsi" , {0}, NULL, 0 },
+ { 5, 8, "rdi" , {0}, NULL, 0 },
+ { 6, 8, "rbp" , {0}, NULL, 1 },
+ { 7, 8, "rsp" , {0}, NULL, 1 },
+ { 8, 8, "r8" , {0}, NULL, 0 },
+ { 9, 8, "r9" , {0}, NULL, 0 },
+ { 10, 8, "r10" , {0}, NULL, 0 },
+ { 11, 8, "r11" , {0}, NULL, 0 },
+ { 12, 8, "r12" , {0}, NULL, 0 },
+ { 13, 8, "r13" , {0}, NULL, 0 },
+ { 14, 8, "r14" , {0}, NULL, 0 },
+ { 15, 8, "r15" , {0}, NULL, 0 },
+ { 16, 8, "rip" , {0}, NULL, 1 },
+ { 17, 4, "rflags", {0}, NULL, 0 },
+ { 18, 4, "cs" , {0}, NULL, 0 },
+ { 19, 4, "ss" , {0}, NULL, 0 },
+ { 20, 4, "ds" , {0}, NULL, 0 },
+ { 21, 4, "es" , {0}, NULL, 0 },
+ { 22, 4, "fs" , {0}, NULL, 0 },
+ { 23, 4, "gs" , {0}, NULL, 0 },
+ { 24, 10, "stmm0" , {0}, NULL, 0 },
+ { 25, 10, "stmm1" , {0}, NULL, 0 },
+ { 26, 10, "stmm2" , {0}, NULL, 0 },
+ { 27, 10, "stmm3" , {0}, NULL, 0 },
+ { 28, 10, "stmm4" , {0}, NULL, 0 },
+ { 29, 10, "stmm5" , {0}, NULL, 0 },
+ { 30, 10, "stmm6" , {0}, NULL, 0 },
+ { 31, 10, "stmm7" , {0}, NULL, 0 },
+ { 32, 4, "fctrl" , {0}, NULL, 0 },
+ { 33, 4, "fstat" , {0}, NULL, 0 },
+ { 34, 4, "ftag" , {0}, NULL, 0 },
+ { 35, 4, "fiseg" , {0}, NULL, 0 },
+ { 36, 4, "fioff" , {0}, NULL, 0 },
+ { 37, 4, "foseg" , {0}, NULL, 0 },
+ { 38, 4, "fooff" , {0}, NULL, 0 },
+ { 39, 4, "fop" , {0}, NULL, 0 },
+ { 40, 16, "xmm0" , {0}, NULL, 0 },
+ { 41, 16, "xmm1" , {0}, NULL, 0 },
+ { 42, 16, "xmm2" , {0}, NULL, 0 },
+ { 43, 16, "xmm3" , {0}, NULL, 0 },
+ { 44, 16, "xmm4" , {0}, NULL, 0 },
+ { 45, 16, "xmm5" , {0}, NULL, 0 },
+ { 46, 16, "xmm6" , {0}, NULL, 0 },
+ { 47, 16, "xmm7" , {0}, NULL, 0 },
+ { 48, 16, "xmm8" , {0}, NULL, 0 },
+ { 49, 16, "xmm9" , {0}, NULL, 0 },
+ { 50, 16, "xmm10" , {0}, NULL, 0 },
+ { 51, 16, "xmm11" , {0}, NULL, 0 },
+ { 52, 16, "xmm12" , {0}, NULL, 0 },
+ { 53, 16, "xmm13" , {0}, NULL, 0 },
+ { 54, 16, "xmm14" , {0}, NULL, 0 },
+ { 55, 16, "xmm15" , {0}, NULL, 0 },
+ { 56, 4, "mxcsr" , {0}, NULL, 0 }
+};
+
+void
+RNBRemote::InitializeRegisters (int use_native_registers)
+{
+ if (use_native_registers)
+ {
+ RNBRemote::InitializeNativeRegisters();
+ }
+ else
+ {
+ const size_t num_regs = sizeof (g_gdb_register_map_x86_64) / sizeof (register_map_entry_t);
+ for (uint32_t i=0; i<num_regs; ++i)
+ {
+ if (!DNBGetRegisterInfoByName (g_gdb_register_map_x86_64[i].gdb_name, &g_gdb_register_map_x86_64[i].nub_info))
+ {
+ RegisterEntryNotAvailable (&g_gdb_register_map_x86_64[i]);
+ assert (g_gdb_register_map_x86_64[i].gdb_size < MAX_REGISTER_BYTE_SIZE);
+ }
+ }
+ g_reg_entries = g_gdb_register_map_x86_64;
+ g_num_reg_entries = sizeof (g_gdb_register_map_x86_64) / sizeof (register_map_entry_t);
+ }
+}
+
+
+#else
+
+void
+RNBRemote::InitializeRegisters (int use_native_registers)
+{
+ // No choice, we don't have a GDB register definition for this arch.
+ RNBRemote::InitializeNativeRegisters();
+}
+
+#endif
+
+
+void
+RNBRemote::InitializeNativeRegisters()
+{
+ if (g_dynamic_register_map.empty())
+ {
+ nub_size_t num_reg_sets = 0;
+ const DNBRegisterSetInfo *reg_sets = DNBGetRegisterSetInfo (&num_reg_sets);
+
+ assert (num_reg_sets > 0 && reg_sets != NULL);
+
+ uint32_t regnum = 0;
+ for (nub_size_t set = 0; set < num_reg_sets; ++set)
+ {
+ if (reg_sets[set].registers == NULL)
+ continue;
+
+ for (uint32_t reg=0; reg < reg_sets[set].num_registers; ++reg)
+ {
+ register_map_entry_t reg_entry = {
+ regnum++, // register number starts at zero and goes up with no gaps
+ reg_sets[set].registers[reg].size, // register size in bytes
+ reg_sets[set].registers[reg].name, // register name
+ reg_sets[set].registers[reg], // DNBRegisterInfo
+ NULL, // Value to print if case we fail to reg this register (if this is NULL, we will return an error)
+ reg_sets[set].registers[reg].reg_generic != INVALID_NUB_REGNUM};
+
+ g_dynamic_register_map.push_back (reg_entry);
+ }
+ }
+ g_reg_entries = g_dynamic_register_map.data();
+ g_num_reg_entries = g_dynamic_register_map.size();
+ }
+}
+
+
+const register_map_entry_t *
+register_mapping_by_regname (const char *n)
+{
+ for (uint32_t reg = 0; reg < g_num_reg_entries; reg++)
+ {
+ if (strcmp (g_reg_entries[reg].gdb_name, n) == 0)
+ return &g_reg_entries[reg];
+ }
+ return NULL;
+}
+
+/* The inferior has stopped executing; send a packet
+ to gdb to let it know. */
+
+void
+RNBRemote::NotifyThatProcessStopped (void)
+{
+ RNBRemote::HandlePacket_last_signal ("");
+ return;
+}
+
+
+/* `A arglen,argnum,arg,...'
+ Update the inferior context CTX with the program name and arg
+ list.
+ The documentation for this packet is underwhelming but my best reading
+ of this is that it is a series of (len, position #, arg)'s, one for
+ each argument with "arg" ``hex encoded'' (two 0-9a-f chars?).
+ Why we need BOTH a "len" and a hex encoded "arg" is beyond me - either
+ is sufficient to get around the "," position separator escape issue.
+
+ e.g. our best guess for a valid 'A' packet for "gdb -q a.out" is
+
+ 6,0,676462,4,1,2d71,10,2,612e6f7574
+
+ Note that "argnum" and "arglen" are numbers in base 10. Again, that's
+ not documented either way but I'm assuming it's so. */
+
+rnb_err_t
+RNBRemote::HandlePacket_A (const char *p)
+{
+ if (p == NULL || *p == '\0')
+ {
+ return HandlePacket_ILLFORMED ("Null packet for 'A' pkt");
+ }
+ p++;
+ if (p == '\0' || !isdigit (*p))
+ {
+ return HandlePacket_ILLFORMED ("arglen not specified on 'A' pkt");
+ }
+
+ /* I promise I don't modify it anywhere in this function. strtoul()'s
+ 2nd arg has to be non-const which makes it problematic to step
+ through the string easily. */
+ char *buf = const_cast<char *>(p);
+
+ RNBContext& ctx = Context();
+
+ while (*buf != '\0')
+ {
+ int arglen, argnum;
+ std::string arg;
+ char *c;
+
+ errno = 0;
+ arglen = strtoul (buf, &c, 10);
+ if (errno != 0 && arglen == 0)
+ {
+ return HandlePacket_ILLFORMED ("arglen not a number on 'A' pkt");
+ }
+ if (*c != ',')
+ {
+ return HandlePacket_ILLFORMED ("arglen not followed by comma on 'A' pkt");
+ }
+ buf = c + 1;
+
+ errno = 0;
+ argnum = strtoul (buf, &c, 10);
+ if (errno != 0 && argnum == 0)
+ {
+ return HandlePacket_ILLFORMED ("argnum not a number on 'A' pkt");
+ }
+ if (*c != ',')
+ {
+ return HandlePacket_ILLFORMED ("arglen not followed by comma on 'A' pkt");
+ }
+ buf = c + 1;
+
+ c = buf;
+ buf = buf + arglen;
+ while (c < buf && *c != '\0' && c + 1 < buf && *(c + 1) != '\0')
+ {
+ char smallbuf[3];
+ smallbuf[0] = *c;
+ smallbuf[1] = *(c + 1);
+ smallbuf[2] = '\0';
+
+ errno = 0;
+ int ch = strtoul (smallbuf, NULL, 16);
+ if (errno != 0 && ch == 0)
+ {
+ return HandlePacket_ILLFORMED ("non-hex char in arg on 'A' pkt");
+ }
+
+ arg.push_back(ch);
+ c += 2;
+ }
+
+ ctx.PushArgument (arg.c_str());
+ if (*buf == ',')
+ buf++;
+ }
+ SendPacket ("OK");
+
+ return rnb_success;
+}
+
+/* `H c t'
+ Set the thread for subsequent actions; 'c' for step/continue ops,
+ 'g' for other ops. -1 means all threads, 0 means any thread. */
+
+rnb_err_t
+RNBRemote::HandlePacket_H (const char *p)
+{
+ p++; // skip 'H'
+ if (*p != 'c' && *p != 'g')
+ {
+ return HandlePacket_ILLFORMED ("Missing 'c' or 'g' type in H packet");
+ }
+
+ if (!m_ctx.HasValidProcessID())
+ {
+ // We allow gdb to connect to a server that hasn't started running
+ // the target yet. gdb still wants to ask questions about it and
+ // freaks out if it gets an error. So just return OK here.
+ }
+
+ errno = 0;
+ nub_thread_t tid = strtoul (p + 1, NULL, 16);
+ if (errno != 0 && tid == 0)
+ {
+ return HandlePacket_ILLFORMED ("Invalid thread number in H packet");
+ }
+ if (*p == 'c')
+ SetContinueThread (tid);
+ if (*p == 'g')
+ SetCurrentThread (tid);
+
+ return SendPacket ("OK");
+}
+
+
+rnb_err_t
+RNBRemote::HandlePacket_qLaunchSuccess (const char *p)
+{
+ if (m_ctx.HasValidProcessID() || m_ctx.LaunchStatus().Error() == 0)
+ return SendPacket("OK");
+ std::ostringstream ret_str;
+ std::string status_str;
+ ret_str << "E" << m_ctx.LaunchStatusAsString(status_str);
+
+ return SendPacket (ret_str.str());
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_qShlibInfoAddr (const char *p)
+{
+ if (m_ctx.HasValidProcessID())
+ {
+ nub_addr_t shlib_info_addr = DNBProcessGetSharedLibraryInfoAddress(m_ctx.ProcessID());
+ if (shlib_info_addr != INVALID_NUB_ADDRESS)
+ {
+ std::ostringstream ostrm;
+ ostrm << RAW_HEXBASE << shlib_info_addr;
+ return SendPacket (ostrm.str ());
+ }
+ }
+ return SendPacket ("E44");
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_qStepPacketSupported (const char *p)
+{
+ // Normally the "s" packet is mandatory, yet in gdb when using ARM, they
+ // get around the need for this packet by implementing software single
+ // stepping from gdb. Current versions of debugserver do support the "s"
+ // packet, yet some older versions do not. We need a way to tell if this
+ // packet is supported so we can disable software single stepping in gdb
+ // for remote targets (so the "s" packet will get used).
+ return SendPacket("OK");
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_qThreadStopInfo (const char *p)
+{
+ p += strlen ("qThreadStopInfo");
+ nub_thread_t tid = strtoul(p, 0, 16);
+ return SendStopReplyPacketForThread (tid);
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_qThreadInfo (const char *p)
+{
+ // We allow gdb to connect to a server that hasn't started running
+ // the target yet. gdb still wants to ask questions about it and
+ // freaks out if it gets an error. So just return OK here.
+ nub_process_t pid = m_ctx.ProcessID();
+ if (pid == INVALID_NUB_PROCESS)
+ return SendPacket ("OK");
+
+ // Only "qfThreadInfo" and "qsThreadInfo" get into this function so
+ // we only need to check the second byte to tell which is which
+ if (p[1] == 'f')
+ {
+ nub_size_t numthreads = DNBProcessGetNumThreads (pid);
+ std::ostringstream ostrm;
+ ostrm << "m";
+ bool first = true;
+ for (nub_size_t i = 0; i < numthreads; ++i)
+ {
+ if (first)
+ first = false;
+ else
+ ostrm << ",";
+ nub_thread_t th = DNBProcessGetThreadAtIndex (pid, i);
+ ostrm << std::hex << th;
+ }
+ return SendPacket (ostrm.str ());
+ }
+ else
+ {
+ return SendPacket ("l");
+ }
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_qThreadExtraInfo (const char *p)
+{
+ // We allow gdb to connect to a server that hasn't started running
+ // the target yet. gdb still wants to ask questions about it and
+ // freaks out if it gets an error. So just return OK here.
+ nub_process_t pid = m_ctx.ProcessID();
+ if (pid == INVALID_NUB_PROCESS)
+ return SendPacket ("OK");
+
+ /* This is supposed to return a string like 'Runnable' or
+ 'Blocked on Mutex'.
+ The returned string is formatted like the "A" packet - a
+ sequence of letters encoded in as 2-hex-chars-per-letter. */
+ p += strlen ("qThreadExtraInfo");
+ if (*p++ != ',')
+ return HandlePacket_ILLFORMED ("Ill formed qThreadExtraInfo packet");
+ errno = 0;
+ nub_thread_t tid = strtoul (p, NULL, 16);
+ if (errno != 0 && tid == 0)
+ {
+ return HandlePacket_ILLFORMED ("Invalid thread number in qThreadExtraInfo packet");
+ }
+
+ const char * threadInfo = DNBThreadGetInfo(pid, tid);
+ if (threadInfo != NULL && threadInfo[0])
+ {
+ return SendHexEncodedBytePacket(NULL, threadInfo, strlen(threadInfo), NULL);
+ }
+ else
+ {
+ // "OK" == 4f6b
+ // Return "OK" as a ASCII hex byte stream if things go wrong
+ return SendPacket ("4f6b");
+ }
+
+ return SendPacket ("");
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_qC (const char *p)
+{
+ nub_process_t pid;
+ std::ostringstream rep;
+ // If we haven't run the process yet, we tell the debugger the
+ // pid is 0. That way it can know to tell use to run later on.
+ if (m_ctx.HasValidProcessID())
+ pid = m_ctx.ProcessID();
+ else
+ pid = 0;
+ rep << "QC" << std::hex << pid;
+ return SendPacket (rep.str());
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_qRegisterInfo (const char *p)
+{
+ p += strlen ("qRegisterInfo");
+
+ nub_size_t num_reg_sets = 0;
+ const DNBRegisterSetInfo *reg_set_info = DNBGetRegisterSetInfo (&num_reg_sets);
+ uint32_t reg_num = strtoul(p, 0, 16);
+
+ if (reg_num < g_num_reg_entries)
+ {
+ const register_map_entry_t *reg_entry = &g_reg_entries[reg_num];
+ std::ostringstream ostrm;
+ ostrm << "name:" << reg_entry->gdb_name << ';';
+
+ if (reg_entry->nub_info.name && ::strcmp (reg_entry->gdb_name, reg_entry->nub_info.name))
+ ostrm << "alt-name:" << reg_entry->nub_info.name << ';';
+ else if (reg_entry->nub_info.alt && ::strcmp (reg_entry->gdb_name, reg_entry->nub_info.alt))
+ ostrm << "alt-name:" << reg_entry->nub_info.alt << ';';
+
+ ostrm << "bitsize:" << std::dec << reg_entry->gdb_size * 8 << ';';
+ ostrm << "offset:" << std::dec << reg_entry->nub_info.offset << ';';
+
+ switch (reg_entry->nub_info.type)
+ {
+ case Uint: ostrm << "encoding:uint;"; break;
+ case Sint: ostrm << "encoding:sint;"; break;
+ case IEEE754: ostrm << "encoding:ieee754;"; break;
+ case Vector: ostrm << "encoding:vector;"; break;
+ }
+
+ switch (reg_entry->nub_info.format)
+ {
+ case Binary: ostrm << "format:binary;"; break;
+ case Decimal: ostrm << "format:decimal;"; break;
+ case Hex: ostrm << "format:hex;"; break;
+ case Float: ostrm << "format:float;"; break;
+ case VectorOfSInt8: ostrm << "format:vector-sint8;"; break;
+ case VectorOfUInt8: ostrm << "format:vector-uint8;"; break;
+ case VectorOfSInt16: ostrm << "format:vector-sint16;"; break;
+ case VectorOfUInt16: ostrm << "format:vector-uint16;"; break;
+ case VectorOfSInt32: ostrm << "format:vector-sint32;"; break;
+ case VectorOfUInt32: ostrm << "format:vector-uint32;"; break;
+ case VectorOfFloat32: ostrm << "format:vector-float32;"; break;
+ case VectorOfUInt128: ostrm << "format:vector-uint128;"; break;
+ };
+
+ if (reg_set_info && reg_entry->nub_info.set < num_reg_sets)
+ ostrm << "set:" << reg_set_info[reg_entry->nub_info.set].name << ';';
+
+
+ if (g_reg_entries != g_dynamic_register_map.data())
+ {
+ if (reg_entry->nub_info.reg_gdb != INVALID_NUB_REGNUM && reg_entry->nub_info.reg_gdb != reg_num)
+ {
+ printf("register %s is getting gdb reg_num of %u when the register info says %u\n",
+ reg_entry->gdb_name, reg_num, reg_entry->nub_info.reg_gdb);
+ }
+ }
+
+ if (reg_entry->nub_info.reg_gcc != INVALID_NUB_REGNUM)
+ ostrm << "gcc:" << std::dec << reg_entry->nub_info.reg_gcc << ';';
+
+ if (reg_entry->nub_info.reg_dwarf != INVALID_NUB_REGNUM)
+ ostrm << "dwarf:" << std::dec << reg_entry->nub_info.reg_dwarf << ';';
+
+
+ switch (reg_entry->nub_info.reg_generic)
+ {
+ case GENERIC_REGNUM_FP: ostrm << "generic:fp;"; break;
+ case GENERIC_REGNUM_PC: ostrm << "generic:pc;"; break;
+ case GENERIC_REGNUM_SP: ostrm << "generic:sp;"; break;
+ case GENERIC_REGNUM_RA: ostrm << "generic:ra;"; break;
+ case GENERIC_REGNUM_FLAGS: ostrm << "generic:flags;"; break;
+ default: break;
+ }
+
+ return SendPacket (ostrm.str ());
+ }
+ return SendPacket ("E45");
+}
+
+
+/* This expects a packet formatted like
+
+ QSetLogging:bitmask=LOG_ALL|LOG_RNB_REMOTE;
+
+ with the "QSetLogging:" already removed from the start. Maybe in the
+ future this packet will include other keyvalue pairs like
+
+ QSetLogging:bitmask=LOG_ALL;mode=asl;
+ */
+
+rnb_err_t
+set_logging (const char *p)
+{
+ int bitmask = 0;
+ while (p && *p != '\0')
+ {
+ if (strncmp (p, "bitmask=", sizeof ("bitmask=") - 1) == 0)
+ {
+ p += sizeof ("bitmask=") - 1;
+ while (p && *p != '\0' && *p != ';')
+ {
+ if (*p == '|')
+ p++;
+ if (strncmp (p, "LOG_VERBOSE", sizeof ("LOG_VERBOSE") - 1) == 0)
+ {
+ p += sizeof ("LOG_VERBOSE") - 1;
+ bitmask |= LOG_VERBOSE;
+ }
+ else if (strncmp (p, "LOG_PROCESS", sizeof ("LOG_PROCESS") - 1) == 0)
+ {
+ p += sizeof ("LOG_PROCESS") - 1;
+ bitmask |= LOG_PROCESS;
+ }
+ else if (strncmp (p, "LOG_THREAD", sizeof ("LOG_THREAD") - 1) == 0)
+ {
+ p += sizeof ("LOG_THREAD") - 1;
+ bitmask |= LOG_THREAD;
+ }
+ else if (strncmp (p, "LOG_EXCEPTIONS", sizeof ("LOG_EXCEPTIONS") - 1) == 0)
+ {
+ p += sizeof ("LOG_EXCEPTIONS") - 1;
+ bitmask |= LOG_EXCEPTIONS;
+ }
+ else if (strncmp (p, "LOG_SHLIB", sizeof ("LOG_SHLIB") - 1) == 0)
+ {
+ p += sizeof ("LOG_SHLIB") - 1;
+ bitmask |= LOG_SHLIB;
+ }
+ else if (strncmp (p, "LOG_MEMORY", sizeof ("LOG_MEMORY") - 1) == 0)
+ {
+ p += sizeof ("LOG_MEMORY") - 1;
+ bitmask |= LOG_MEMORY;
+ }
+ else if (strncmp (p, "LOG_MEMORY_DATA_SHORT", sizeof ("LOG_MEMORY_DATA_SHORT") - 1) == 0)
+ {
+ p += sizeof ("LOG_MEMORY_DATA_SHORT") - 1;
+ bitmask |= LOG_MEMORY_DATA_SHORT;
+ }
+ else if (strncmp (p, "LOG_MEMORY_DATA_LONG", sizeof ("LOG_MEMORY_DATA_LONG") - 1) == 0)
+ {
+ p += sizeof ("LOG_MEMORY_DATA_LONG") - 1;
+ bitmask |= LOG_MEMORY_DATA_LONG;
+ }
+ else if (strncmp (p, "LOG_BREAKPOINTS", sizeof ("LOG_BREAKPOINTS") - 1) == 0)
+ {
+ p += sizeof ("LOG_BREAKPOINTS") - 1;
+ bitmask |= LOG_BREAKPOINTS;
+ }
+ else if (strncmp (p, "LOG_ALL", sizeof ("LOG_ALL") - 1) == 0)
+ {
+ p += sizeof ("LOG_ALL") - 1;
+ bitmask |= LOG_ALL;
+ }
+ else if (strncmp (p, "LOG_EVENTS", sizeof ("LOG_EVENTS") - 1) == 0)
+ {
+ p += sizeof ("LOG_EVENTS") - 1;
+ bitmask |= LOG_EVENTS;
+ }
+ else if (strncmp (p, "LOG_DEFAULT", sizeof ("LOG_DEFAULT") - 1) == 0)
+ {
+ p += sizeof ("LOG_DEFAULT") - 1;
+ bitmask |= LOG_DEFAULT;
+ }
+ else if (strncmp (p, "LOG_NONE", sizeof ("LOG_NONE") - 1) == 0)
+ {
+ p += sizeof ("LOG_NONE") - 1;
+ bitmask = 0;
+ }
+ else if (strncmp (p, "LOG_RNB_MINIMAL", sizeof ("LOG_RNB_MINIMAL") - 1) == 0)
+ {
+ p += sizeof ("LOG_RNB_MINIMAL") - 1;
+ bitmask |= LOG_RNB_MINIMAL;
+ }
+ else if (strncmp (p, "LOG_RNB_MEDIUM", sizeof ("LOG_RNB_MEDIUM") - 1) == 0)
+ {
+ p += sizeof ("LOG_RNB_MEDIUM") - 1;
+ bitmask |= LOG_RNB_MEDIUM;
+ }
+ else if (strncmp (p, "LOG_RNB_MAX", sizeof ("LOG_RNB_MAX") - 1) == 0)
+ {
+ p += sizeof ("LOG_RNB_MAX") - 1;
+ bitmask |= LOG_RNB_MAX;
+ }
+ else if (strncmp (p, "LOG_RNB_COMM", sizeof ("LOG_RNB_COMM") - 1) == 0)
+ {
+ p += sizeof ("LOG_RNB_COMM") - 1;
+ bitmask |= LOG_RNB_COMM;
+ }
+ else if (strncmp (p, "LOG_RNB_REMOTE", sizeof ("LOG_RNB_REMOTE") - 1) == 0)
+ {
+ p += sizeof ("LOG_RNB_REMOTE") - 1;
+ bitmask |= LOG_RNB_REMOTE;
+ }
+ else if (strncmp (p, "LOG_RNB_EVENTS", sizeof ("LOG_RNB_EVENTS") - 1) == 0)
+ {
+ p += sizeof ("LOG_RNB_EVENTS") - 1;
+ bitmask |= LOG_RNB_EVENTS;
+ }
+ else if (strncmp (p, "LOG_RNB_PROC", sizeof ("LOG_RNB_PROC") - 1) == 0)
+ {
+ p += sizeof ("LOG_RNB_PROC") - 1;
+ bitmask |= LOG_RNB_PROC;
+ }
+ else if (strncmp (p, "LOG_RNB_PACKETS", sizeof ("LOG_RNB_PACKETS") - 1) == 0)
+ {
+ p += sizeof ("LOG_RNB_PACKETS") - 1;
+ bitmask |= LOG_RNB_PACKETS;
+ }
+ else if (strncmp (p, "LOG_RNB_ALL", sizeof ("LOG_RNB_ALL") - 1) == 0)
+ {
+ p += sizeof ("LOG_RNB_ALL") - 1;
+ bitmask |= LOG_RNB_ALL;
+ }
+ else if (strncmp (p, "LOG_RNB_DEFAULT", sizeof ("LOG_RNB_DEFAULT") - 1) == 0)
+ {
+ p += sizeof ("LOG_RNB_DEFAULT") - 1;
+ bitmask |= LOG_RNB_DEFAULT;
+ }
+ else if (strncmp (p, "LOG_RNB_NONE", sizeof ("LOG_RNB_NONE") - 1) == 0)
+ {
+ p += sizeof ("LOG_RNB_NONE") - 1;
+ bitmask = 0;
+ }
+ else
+ {
+ /* Unrecognized logging bit; ignore it. */
+ const char *c = strchr (p, '|');
+ if (c)
+ {
+ p = c;
+ }
+ else
+ {
+ c = strchr (p, ';');
+ if (c)
+ {
+ p = c;
+ }
+ else
+ {
+ // Improperly terminated word; just go to end of str
+ p = strchr (p, '\0');
+ }
+ }
+ }
+ }
+ // Did we get a properly formatted logging bitmask?
+ if (*p == ';')
+ {
+ // Enable DNB logging
+ DNBLogSetLogCallback(ASLLogCallback, NULL);
+ DNBLogSetLogMask (bitmask);
+ p++;
+ }
+ }
+ // We're not going to support logging to a file for now. All logging
+ // goes through ASL.
+#if 0
+ else if (strncmp (p, "mode=", sizeof ("mode=") - 1) == 0)
+ {
+ p += sizeof ("mode=") - 1;
+ if (strncmp (p, "asl;", sizeof ("asl;") - 1) == 0)
+ {
+ DNBLogToASL ();
+ p += sizeof ("asl;") - 1;
+ }
+ else if (strncmp (p, "file;", sizeof ("file;") - 1) == 0)
+ {
+ DNBLogToFile ();
+ p += sizeof ("file;") - 1;
+ }
+ else
+ {
+ // Ignore unknown argument
+ const char *c = strchr (p, ';');
+ if (c)
+ p = c + 1;
+ else
+ p = strchr (p, '\0');
+ }
+ }
+ else if (strncmp (p, "filename=", sizeof ("filename=") - 1) == 0)
+ {
+ p += sizeof ("filename=") - 1;
+ const char *c = strchr (p, ';');
+ if (c == NULL)
+ {
+ c = strchr (p, '\0');
+ continue;
+ }
+ char *fn = (char *) alloca (c - p + 1);
+ strncpy (fn, p, c - p);
+ fn[c - p] = '\0';
+
+ // A file name of "asl" is special and is another way to indicate
+ // that logging should be done via ASL, not by file.
+ if (strcmp (fn, "asl") == 0)
+ {
+ DNBLogToASL ();
+ }
+ else
+ {
+ FILE *f = fopen (fn, "w");
+ if (f)
+ {
+ DNBLogSetLogFile (f);
+ DNBEnableLogging (f, DNBLogGetLogMask ());
+ DNBLogToFile ();
+ }
+ }
+ p = c + 1;
+ }
+#endif /* #if 0 to enforce ASL logging only. */
+ else
+ {
+ // Ignore unknown argument
+ const char *c = strchr (p, ';');
+ if (c)
+ p = c + 1;
+ else
+ p = strchr (p, '\0');
+ }
+ }
+
+ return rnb_success;
+}
+
+
+
+rnb_err_t
+RNBRemote::HandlePacket_Q (const char *p)
+{
+ if (p == NULL || strlen (p) <= 1)
+ {
+ return HandlePacket_ILLFORMED ("No subtype specified in Q packet");
+ }
+
+ /* Switch to no-ack protocol mode after the "OK" packet is sent
+ and the ack for that comes back from gdb. */
+
+ if (strcmp (p, "QStartNoAckMode") == 0)
+ {
+ rnb_err_t result = SendPacket ("OK");
+ m_noack_mode = true;
+ return result;
+ }
+
+ if (strncmp (p, "QSetLogging:", sizeof ("QSetLogging:") - 1) == 0)
+ {
+ p += sizeof ("QSetLogging:") - 1;
+ rnb_err_t result = set_logging (p);
+ if (result == rnb_success)
+ return SendPacket ("OK");
+ else
+ return SendPacket ("E35");
+ }
+
+ /* The number of characters in a packet payload that gdb is
+ prepared to accept. The packet-start char, packet-end char,
+ 2 checksum chars and terminating null character are not included
+ in this size. */
+ if (strncmp (p, "QSetMaxPayloadSize:", sizeof ("QSetMaxPayloadSize:") - 1) == 0)
+ {
+ p += sizeof ("QSetMaxPayloadSize:") - 1;
+ errno = 0;
+ uint32_t size = strtoul (p, NULL, 16);
+ if (errno != 0 && size == 0)
+ {
+ return HandlePacket_ILLFORMED ("Invalid length in QSetMaxPayloadSize packet");
+ }
+ m_max_payload_size = size;
+ return SendPacket ("OK");
+ }
+
+ /* This tells us the largest packet that gdb can handle.
+ i.e. the size of gdb's packet-reading buffer.
+ QSetMaxPayloadSize is preferred because it is less ambiguous. */
+
+ if (strncmp (p, "QSetMaxPacketSize:", sizeof ("QSetMaxPacketSize:") - 1) == 0)
+ {
+ p += sizeof ("QSetMaxPacketSize:") - 1;
+ errno = 0;
+ uint32_t size = strtoul (p, NULL, 16);
+ if (errno != 0 && size == 0)
+ {
+ return HandlePacket_ILLFORMED ("Invalid length in QSetMaxPacketSize packet");
+ }
+ m_max_payload_size = size - 5;
+ return SendPacket ("OK");
+ }
+
+ /* This sets the environment for the target program. The packet is of the form:
+
+ QEnvironment:VARIABLE=VALUE
+
+ */
+
+ if (strncmp (p, "QEnvironment:", sizeof ("QEnvironment:") - 1) == 0)
+ {
+ DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s Handling QEnvironment: \"%s\"",
+ (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, p);
+
+ p += sizeof ("QEnvironment:") - 1;
+ RNBContext& ctx = Context();
+
+ ctx.PushEnvironment (p);
+ return SendPacket ("OK");
+ }
+
+ // Unrecognized Q packet
+ return SendPacket ("");
+}
+
+void
+append_hex_value (std::ostream& ostrm, const uint8_t* buf, size_t buf_size, bool swap)
+{
+ int i;
+ if (swap)
+ {
+ for (i = buf_size-1; i >= 0; i--)
+ ostrm << RAWHEX8(buf[i]);
+ }
+ else
+ {
+ for (i = 0; i < buf_size; i++)
+ ostrm << RAWHEX8(buf[i]);
+ }
+}
+
+
+void
+register_value_in_hex_fixed_width
+(
+ std::ostream& ostrm,
+ nub_process_t pid,
+ nub_thread_t tid,
+ const register_map_entry_t* reg
+ )
+{
+ if (reg != NULL)
+ {
+ DNBRegisterValue val;
+ if (DNBThreadGetRegisterValueByID (pid, tid, reg->nub_info.set, reg->nub_info.reg, &val))
+ {
+ append_hex_value (ostrm, val.value.v_uint8, reg->gdb_size, false);
+ }
+ else
+ {
+ // If we fail to read a regiser value, check if it has a default
+ // fail value. If it does, return this instead in case some of
+ // the registers are not available on the current system.
+ if (reg->gdb_size > 0)
+ {
+ if (reg->fail_value != NULL)
+ {
+ append_hex_value (ostrm, reg->fail_value, reg->gdb_size, false);
+ }
+ else
+ {
+ std::basic_string<uint8_t> zeros(reg->gdb_size, '\0');
+ append_hex_value (ostrm, zeros.data(), zeros.size(), false);
+ }
+ }
+ }
+ }
+}
+
+
+void
+gdb_regnum_with_fixed_width_hex_register_value
+(
+ std::ostream& ostrm,
+ nub_process_t pid,
+ nub_thread_t tid,
+ const register_map_entry_t* reg
+ )
+{
+ // Output the register number as 'NN:VVVVVVVV;' where NN is a 2 bytes HEX
+ // gdb register number, and VVVVVVVV is the correct number of hex bytes
+ // as ASCII for the register value.
+ if (reg != NULL)
+ {
+ ostrm << RAWHEX8(reg->gdb_regnum) << ':';
+ register_value_in_hex_fixed_width (ostrm, pid, tid, reg);
+ ostrm << ';';
+ }
+}
+
+rnb_err_t
+RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid)
+{
+ const nub_process_t pid = m_ctx.ProcessID();
+ if (pid == INVALID_NUB_PROCESS)
+ return SendPacket("E50");
+
+ struct DNBThreadStopInfo tid_stop_info;
+
+ /* Fill the remaining space in this packet with as many registers
+ as we can stuff in there. */
+
+ if (DNBThreadGetStopReason (pid, tid, &tid_stop_info))
+ {
+ std::ostringstream ostrm;
+ // Output the T packet with the thread
+ ostrm << 'T';
+ int signum = tid_stop_info.details.signal.signo;
+ DNBLogThreadedIf (LOG_RNB_PROC, "%8d %s got signal signo = %u, exc_type = %u", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, tid_stop_info.details.signal.signo, tid_stop_info.details.exception.type);
+
+ // Translate any mach exceptions to gdb versions, unless they are
+ // common exceptions like a breakpoint or a soft signal.
+ switch (tid_stop_info.details.exception.type)
+ {
+ default: signum = 0; break;
+ case EXC_BREAKPOINT: signum = SIGTRAP; break;
+ case EXC_BAD_ACCESS: signum = TARGET_EXC_BAD_ACCESS; break;
+ case EXC_BAD_INSTRUCTION: signum = TARGET_EXC_BAD_INSTRUCTION; break;
+ case EXC_ARITHMETIC: signum = TARGET_EXC_ARITHMETIC; break;
+ case EXC_EMULATION: signum = TARGET_EXC_EMULATION; break;
+ case EXC_SOFTWARE:
+ if (tid_stop_info.details.exception.data_count == 2 &&
+ tid_stop_info.details.exception.data[0] == EXC_SOFT_SIGNAL)
+ signum = tid_stop_info.details.exception.data[1];
+ else
+ signum = TARGET_EXC_SOFTWARE;
+ break;
+ }
+
+ ostrm << RAWHEX8(signum & 0xff);
+
+ ostrm << std::hex << "thread:" << tid << ';';
+
+ const char *thread_name = DNBThreadGetName (pid, tid);
+ if (thread_name && thread_name[0])
+ ostrm << std::hex << "name:" << thread_name << ';';
+
+ thread_identifier_info_data_t thread_ident_info;
+ if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info))
+ {
+ if (thread_ident_info.dispatch_qaddr != 0)
+ ostrm << std::hex << "dispatchqaddr:" << thread_ident_info.dispatch_qaddr << ';';
+ }
+ DNBRegisterValue reg_value;
+ for (uint32_t reg = 0; reg < g_num_reg_entries; reg++)
+ {
+ if (g_reg_entries[reg].expedite)
+ {
+ if (!DNBThreadGetRegisterValueByID (pid, tid, g_reg_entries[reg].nub_info.set, g_reg_entries[reg].nub_info.reg, &reg_value))
+ continue;
+
+ gdb_regnum_with_fixed_width_hex_register_value (ostrm, pid, tid, &g_reg_entries[reg]);
+ }
+ }
+
+ if (tid_stop_info.details.exception.type)
+ {
+ ostrm << "metype:" << std::hex << tid_stop_info.details.exception.type << ";";
+ ostrm << "mecount:" << std::hex << tid_stop_info.details.exception.data_count << ";";
+ for (int i = 0; i < tid_stop_info.details.exception.data_count; ++i)
+ ostrm << "medata:" << std::hex << tid_stop_info.details.exception.data[i] << ";";
+ }
+ return SendPacket (ostrm.str ());
+ }
+ return SendPacket("E51");
+}
+
+/* `?'
+ The stop reply packet - tell gdb what the status of the inferior is.
+ Often called the questionmark_packet. */
+
+rnb_err_t
+RNBRemote::HandlePacket_last_signal (const char *unused)
+{
+ if (!m_ctx.HasValidProcessID())
+ {
+ // Inferior is not yet specified/running
+ return SendPacket ("E02");
+ }
+
+ nub_process_t pid = m_ctx.ProcessID();
+ nub_state_t pid_state = DNBProcessGetState (pid);
+
+ switch (pid_state)
+ {
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ return rnb_success; // Ignore
+
+ case eStateSuspended:
+ case eStateStopped:
+ case eStateCrashed:
+ {
+ nub_thread_t tid = DNBProcessGetCurrentThread (pid);
+ // Make sure we set the current thread so g and p packets return
+ // the data the gdb will expect.
+ SetCurrentThread (tid);
+
+ SendStopReplyPacketForThread (tid);
+ }
+ break;
+
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateExited:
+ {
+ char pid_exited_packet[16] = "";
+ int pid_status = 0;
+ // Process exited with exit status
+ if (!DNBProcessGetExitStatus(pid, &pid_status))
+ pid_status = 0;
+
+ if (pid_status)
+ {
+ if (WIFEXITED (pid_status))
+ snprintf (pid_exited_packet, sizeof(pid_exited_packet), "W%02x", WEXITSTATUS (pid_status));
+ else if (WIFSIGNALED (pid_status))
+ snprintf (pid_exited_packet, sizeof(pid_exited_packet), "X%02x", WEXITSTATUS (pid_status));
+ else if (WIFSTOPPED (pid_status))
+ snprintf (pid_exited_packet, sizeof(pid_exited_packet), "S%02x", WSTOPSIG (pid_status));
+ }
+
+ // If we have an empty exit packet, lets fill one in to be safe.
+ if (!pid_exited_packet[0])
+ {
+ strncpy (pid_exited_packet, "W00", sizeof(pid_exited_packet)-1);
+ pid_exited_packet[sizeof(pid_exited_packet)-1] = '\0';
+ }
+
+ return SendPacket (pid_exited_packet);
+ }
+ break;
+ }
+ return rnb_success;
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_M (const char *p)
+{
+ if (p == NULL || p[0] == '\0' || strlen (p) < 3)
+ {
+ return HandlePacket_ILLFORMED ("Too short M packet");
+ }
+
+ char *c;
+ p++;
+ errno = 0;
+ nub_addr_t addr = strtoull (p, &c, 16);
+ if (errno != 0 && addr == 0)
+ {
+ return HandlePacket_ILLFORMED ("Invalid address in M packet");
+ }
+ if (*c != ',')
+ {
+ return HandlePacket_ILLFORMED ("Comma sep missing in M packet");
+ }
+
+ /* Advance 'p' to the length part of the packet. */
+ p += (c - p) + 1;
+
+ errno = 0;
+ uint32_t length = strtoul (p, &c, 16);
+ if (errno != 0 && length == 0)
+ {
+ return HandlePacket_ILLFORMED ("Invalid length in M packet");
+ }
+ if (length == 0)
+ {
+ return SendPacket ("OK");
+ }
+
+ if (*c != ':')
+ {
+ return HandlePacket_ILLFORMED ("Missing colon in M packet");
+ }
+ /* Advance 'p' to the data part of the packet. */
+ p += (c - p) + 1;
+
+ int datalen = strlen (p);
+ if (datalen & 0x1)
+ {
+ return HandlePacket_ILLFORMED ("Uneven # of hex chars for data in M packet");
+ }
+ if (datalen == 0)
+ {
+ return SendPacket ("OK");
+ }
+
+ uint8_t *buf = (uint8_t *) alloca (datalen / 2);
+ uint8_t *i = buf;
+
+ while (*p != '\0' && *(p + 1) != '\0')
+ {
+ char hexbuf[3];
+ hexbuf[0] = *p;
+ hexbuf[1] = *(p + 1);
+ hexbuf[2] = '\0';
+ errno = 0;
+ uint8_t byte = strtoul (hexbuf, NULL, 16);
+ if (errno != 0 && byte == 0)
+ {
+ return HandlePacket_ILLFORMED ("Invalid hex byte in M packet");
+ }
+ *i++ = byte;
+ p += 2;
+ }
+
+ nub_size_t wrote = DNBProcessMemoryWrite (m_ctx.ProcessID(), addr, length, buf);
+ if (wrote != length)
+ return SendPacket ("E09");
+ else
+ return SendPacket ("OK");
+}
+
+
+rnb_err_t
+RNBRemote::HandlePacket_m (const char *p)
+{
+ if (p == NULL || p[0] == '\0' || strlen (p) < 3)
+ {
+ return HandlePacket_ILLFORMED ("Too short m packet");
+ }
+
+ char *c;
+ p++;
+ errno = 0;
+ nub_addr_t addr = strtoull (p, &c, 16);
+ if (errno != 0 && addr == 0)
+ {
+ return HandlePacket_ILLFORMED ("Invalid address in m packet");
+ }
+ if (*c != ',')
+ {
+ return HandlePacket_ILLFORMED ("Comma sep missing in m packet");
+ }
+
+ /* Advance 'p' to the length part of the packet. */
+ p += (c - p) + 1;
+
+ errno = 0;
+ uint32_t length = strtoul (p, NULL, 16);
+ if (errno != 0 && length == 0)
+ {
+ return HandlePacket_ILLFORMED ("Invalid length in m packet");
+ }
+ if (length == 0)
+ {
+ return SendPacket ("");
+ }
+
+ uint8_t buf[length];
+ int bytes_read = DNBProcessMemoryRead (m_ctx.ProcessID(), addr, length, buf);
+ if (bytes_read == 0)
+ {
+ return SendPacket ("E08");
+ }
+
+ // "The reply may contain fewer bytes than requested if the server was able
+ // to read only part of the region of memory."
+ length = bytes_read;
+
+ std::ostringstream ostrm;
+ for (int i = 0; i < length; i++)
+ ostrm << RAWHEX8(buf[i]);
+ return SendPacket (ostrm.str ());
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_X (const char *p)
+{
+ if (p == NULL || p[0] == '\0' || strlen (p) < 3)
+ {
+ return HandlePacket_ILLFORMED ("Too short X packet");
+ }
+
+ char *c;
+ p++;
+ errno = 0;
+ nub_addr_t addr = strtoull (p, &c, 16);
+ if (errno != 0 && addr == 0)
+ {
+ return HandlePacket_ILLFORMED ("Invalid address in X packet");
+ }
+ if (*c != ',')
+ {
+ return HandlePacket_ILLFORMED ("Comma sep missing in X packet");
+ }
+
+ /* Advance 'p' to the length part of the packet. */
+ p += (c - p) + 1;
+
+ errno = 0;
+ int length = strtoul (p, NULL, 16);
+ if (errno != 0 && length == 0)
+ {
+ return HandlePacket_ILLFORMED ("Invalid length in m packet");
+ }
+
+ // I think gdb sends a zero length write request to test whether this
+ // packet is accepted.
+ if (length == 0)
+ {
+ return SendPacket ("OK");
+ }
+
+ std::vector<uint8_t> data = decode_binary_data (c, -1);
+ std::vector<uint8_t>::const_iterator it;
+ uint8_t *buf = (uint8_t *) alloca (data.size ());
+ uint8_t *i = buf;
+ for (it = data.begin (); it != data.end (); ++it)
+ {
+ *i++ = *it;
+ }
+
+ nub_size_t wrote = DNBProcessMemoryWrite (m_ctx.ProcessID(), addr, data.size(), buf);
+ if (wrote != data.size ())
+ return SendPacket ("E08");
+ return SendPacket ("OK");
+}
+
+/* `g' -- read registers
+ Get the contents of the registers for the current thread,
+ send them to gdb.
+ Should the setting of the Hg packet determine which thread's registers
+ are returned? */
+
+rnb_err_t
+RNBRemote::HandlePacket_g (const char *p)
+{
+ std::ostringstream ostrm;
+ if (!m_ctx.HasValidProcessID())
+ {
+ return SendPacket ("E11");
+ }
+ nub_process_t pid = m_ctx.ProcessID ();
+ nub_thread_t tid = GetCurrentThread();
+
+ if (m_use_native_regs)
+ {
+ // Get the register context size first by calling with NULL buffer
+ nub_size_t reg_ctx_size = DNBThreadGetRegisterContext(pid, tid, NULL, 0);
+ if (reg_ctx_size)
+ {
+ // Now allocate enough space for the entire register context
+ std::vector<uint8_t> reg_ctx;
+ reg_ctx.resize(reg_ctx_size);
+ // Now read the register context
+ reg_ctx_size = DNBThreadGetRegisterContext(pid, tid, &reg_ctx[0], reg_ctx.size());
+ if (reg_ctx_size)
+ {
+ append_hex_value (ostrm, reg_ctx.data(), reg_ctx.size(), false);
+ return SendPacket (ostrm.str ());
+ }
+ }
+ }
+
+ for (uint32_t reg = 0; reg < g_num_reg_entries; reg++)
+ register_value_in_hex_fixed_width (ostrm, pid, tid, &g_reg_entries[reg]);
+
+ return SendPacket (ostrm.str ());
+}
+
+/* `G XXX...' -- write registers
+ How is the thread for these specified, beyond "the current thread"?
+ Does gdb actually use the Hg packet to set this? */
+
+rnb_err_t
+RNBRemote::HandlePacket_G (const char *p)
+{
+ if (!m_ctx.HasValidProcessID())
+ {
+ return SendPacket ("E11");
+ }
+ StringExtractor packet(p);
+ packet.SetFilePos(1); // Skip the 'G'
+
+ nub_process_t pid = m_ctx.ProcessID();
+ nub_thread_t tid = GetCurrentThread();
+
+ if (m_use_native_regs)
+ {
+ // Get the register context size first by calling with NULL buffer
+ nub_size_t reg_ctx_size = DNBThreadGetRegisterContext(pid, tid, NULL, 0);
+ if (reg_ctx_size)
+ {
+ // Now allocate enough space for the entire register context
+ std::vector<uint8_t> reg_ctx;
+ reg_ctx.resize(reg_ctx_size);
+
+ if (packet.GetHexBytes (&reg_ctx[0], reg_ctx.size(), 0xcc) == reg_ctx.size())
+ {
+ // Now write the register context
+ reg_ctx_size = DNBThreadSetRegisterContext(pid, tid, reg_ctx.data(), reg_ctx.size());
+ if (reg_ctx_size == reg_ctx.size())
+ return SendPacket ("OK");
+ else
+ return SendPacket ("E55");
+ }
+ }
+ }
+
+
+ DNBRegisterValue reg_value;
+ for (uint32_t reg = 0; reg < g_num_reg_entries; reg++)
+ {
+ const register_map_entry_t *reg_entry = &g_reg_entries[reg];
+
+ reg_value.info = reg_entry->nub_info;
+ if (packet.GetHexBytes (reg_value.value.v_sint8, reg_entry->gdb_size, 0xcc) != reg_entry->gdb_size)
+ break;
+
+ if (!DNBThreadSetRegisterValueByID (pid, tid, reg_entry->nub_info.set, reg_entry->nub_info.reg, &reg_value))
+ return SendPacket ("E15");
+ }
+ return SendPacket ("OK");
+}
+
+static bool
+RNBRemoteShouldCancelCallback (void *not_used)
+{
+ RNBRemoteSP remoteSP(g_remoteSP);
+ if (remoteSP.get() != NULL)
+ {
+ RNBRemote* remote = remoteSP.get();
+ if (remote->Comm().IsConnected())
+ return false;
+ else
+ return true;
+ }
+ return true;
+}
+
+
+// FORMAT: _MXXXXXX,PPP
+// XXXXXX: big endian hex chars
+// PPP: permissions can be any combo of r w x chars
+//
+// RESPONSE: XXXXXX
+// XXXXXX: hex address of the newly allocated memory
+// EXX: error code
+//
+// EXAMPLES:
+// _M123000,rw
+// _M123000,rwx
+// _M123000,xw
+
+rnb_err_t
+RNBRemote::HandlePacket_AllocateMemory (const char *p)
+{
+ StringExtractor packet (p);
+ packet.SetFilePos(2); // Skip the "_M"
+
+ nub_addr_t size = packet.GetHexMaxU64 (StringExtractor::BigEndian, 0);
+ if (size != 0)
+ {
+ if (packet.GetChar() == ',')
+ {
+ uint32_t permissions = 0;
+ char ch;
+ bool success = true;
+ while (success && (ch = packet.GetChar()) != '\0')
+ {
+ switch (ch)
+ {
+ case 'r': permissions |= eMemoryPermissionsReadable; break;
+ case 'w': permissions |= eMemoryPermissionsWritable; break;
+ case 'x': permissions |= eMemoryPermissionsExecutable; break;
+ default: success = false; break;
+ }
+ }
+
+ if (success)
+ {
+ nub_addr_t addr = DNBProcessMemoryAllocate (m_ctx.ProcessID(), size, permissions);
+ if (addr != INVALID_NUB_ADDRESS)
+ {
+ std::ostringstream ostrm;
+ ostrm << RAW_HEXBASE << addr;
+ return SendPacket (ostrm.str ());
+ }
+ }
+ }
+ }
+ return SendPacket ("E53");
+}
+
+// FORMAT: _mXXXXXX
+// XXXXXX: address that was previosly allocated
+//
+// RESPONSE: XXXXXX
+// OK: address was deallocated
+// EXX: error code
+//
+// EXAMPLES:
+// _m123000
+
+rnb_err_t
+RNBRemote::HandlePacket_DeallocateMemory (const char *p)
+{
+ StringExtractor packet (p);
+ packet.SetFilePos(2); // Skip the "_m"
+ nub_addr_t addr = packet.GetHexMaxU64 (StringExtractor::BigEndian, INVALID_NUB_ADDRESS);
+
+ if (addr != INVALID_NUB_ADDRESS)
+ {
+ if (DNBProcessMemoryDeallocate (m_ctx.ProcessID(), addr))
+ return SendPacket ("OK");
+ }
+ return SendPacket ("E54");
+}
+
+/*
+ vAttach;pid
+
+ Attach to a new process with the specified process ID. pid is a hexadecimal integer
+ identifying the process. If the stub is currently controlling a process, it is
+ killed. The attached process is stopped.This packet is only available in extended
+ mode (see extended mode).
+
+ Reply:
+ "ENN" for an error
+ "Any Stop Reply Packet" for success
+ */
+
+rnb_err_t
+RNBRemote::HandlePacket_v (const char *p)
+{
+ if (strcmp (p, "vCont;c") == 0)
+ {
+ // Simple continue
+ return RNBRemote::HandlePacket_c("c");
+ }
+ else if (strcmp (p, "vCont;s") == 0)
+ {
+ // Simple step
+ return RNBRemote::HandlePacket_s("s");
+ }
+ else if (strstr (p, "vCont") == p)
+ {
+ rnb_err_t rnb_err = rnb_success;
+ typedef struct
+ {
+ nub_thread_t tid;
+ char action;
+ int signal;
+ } vcont_action_t;
+
+ DNBThreadResumeActions thread_actions;
+ char *c = (char *)(p += strlen("vCont"));
+ char *c_end = c + strlen(c);
+ if (*c == '?')
+ return SendPacket ("vCont;c;C;s;S");
+
+ while (c < c_end && *c == ';')
+ {
+ ++c; // Skip the semi-colon
+ DNBThreadResumeAction thread_action;
+ thread_action.tid = INVALID_NUB_THREAD;
+ thread_action.state = eStateInvalid;
+ thread_action.signal = 0;
+ thread_action.addr = INVALID_NUB_ADDRESS;
+
+ char action = *c++;
+
+ switch (action)
+ {
+ case 'C':
+ errno = 0;
+ thread_action.signal = strtoul (c, &c, 16);
+ if (errno != 0)
+ return HandlePacket_ILLFORMED ("Could not parse signal in vCont packet");
+ // Fall through to next case...
+
+ case 'c':
+ // Continue
+ thread_action.state = eStateRunning;
+ break;
+
+ case 'S':
+ errno = 0;
+ thread_action.signal = strtoul (c, &c, 16);
+ if (errno != 0)
+ return HandlePacket_ILLFORMED ("Could not parse signal in vCont packet");
+ // Fall through to next case...
+
+ case 's':
+ // Step
+ thread_action.state = eStateStepping;
+ break;
+
+ break;
+
+ default:
+ rnb_err = HandlePacket_ILLFORMED ("Unsupported action in vCont packet");
+ break;
+ }
+ if (*c == ':')
+ {
+ errno = 0;
+ thread_action.tid = strtoul (++c, &c, 16);
+ if (errno != 0)
+ return HandlePacket_ILLFORMED ("Could not parse thread number in vCont packet");
+ }
+
+ thread_actions.Append (thread_action);
+ }
+
+ // If a default action for all other threads wasn't mentioned
+ // then we should stop the threads
+ thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0);
+ DNBProcessResume(m_ctx.ProcessID(), thread_actions.GetFirst (), thread_actions.GetSize());
+ return rnb_success;
+ }
+ else if (strstr (p, "vAttach") == p)
+ {
+ nub_process_t attach_pid = INVALID_NUB_PROCESS;
+ char err_str[1024]={'\0'};
+ if (strstr (p, "vAttachWait;") == p)
+ {
+ p += strlen("vAttachWait;");
+ std::string attach_name;
+ while (*p != '\0')
+ {
+ char smallbuf[3];
+ smallbuf[0] = *p;
+ smallbuf[1] = *(p + 1);
+ smallbuf[2] = '\0';
+
+ errno = 0;
+ int ch = strtoul (smallbuf, NULL, 16);
+ if (errno != 0 && ch == 0)
+ {
+ return HandlePacket_ILLFORMED ("non-hex char in arg on 'vAttachWait' pkt");
+ }
+
+ attach_name.push_back(ch);
+ p += 2;
+ }
+
+ attach_pid = DNBProcessAttachWait(attach_name.c_str (), m_ctx.LaunchFlavor(), NULL, 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback);
+
+ }
+ else if (strstr (p, "vAttach;") == p)
+ {
+ p += strlen("vAttach;");
+ char *end = NULL;
+ attach_pid = strtoul (p, &end, 16); // PID will be in hex, so use base 16 to decode
+ if (p != end && *end == '\0')
+ {
+ // Wait at most 30 second for attach
+ struct timespec attach_timeout_abstime;
+ DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, 30, 0);
+ attach_pid = DNBProcessAttach(attach_pid, &attach_timeout_abstime, err_str, sizeof(err_str));
+ }
+ }
+ else
+ return HandlePacket_UNIMPLEMENTED(p);
+
+
+ if (attach_pid != INVALID_NUB_PROCESS)
+ {
+ if (m_ctx.ProcessID() != attach_pid)
+ m_ctx.SetProcessID(attach_pid);
+ // Send a stop reply packet to indicate we successfully attached!
+ NotifyThatProcessStopped ();
+ return rnb_success;
+ }
+ else
+ {
+ m_ctx.LaunchStatus().SetError(-1, DNBError::Generic);
+ if (err_str[0])
+ m_ctx.LaunchStatus().SetErrorString(err_str);
+ else
+ m_ctx.LaunchStatus().SetErrorString("attach failed");
+ return SendPacket ("E01"); // E01 is our magic error value for attach failed.
+ }
+ }
+
+ // All other failures come through here
+ return HandlePacket_UNIMPLEMENTED(p);
+}
+
+/* `T XX' -- status of thread
+ Check if the specified thread is alive.
+ The thread number is in hex? */
+
+rnb_err_t
+RNBRemote::HandlePacket_T (const char *p)
+{
+ p++;
+ if (p == NULL || *p == '\0')
+ {
+ return HandlePacket_ILLFORMED ("No thread specified in T packet");
+ }
+ if (!m_ctx.HasValidProcessID())
+ {
+ return SendPacket ("E15");
+ }
+ errno = 0;
+ nub_thread_t tid = strtoul (p, NULL, 16);
+ if (errno != 0 && tid == 0)
+ {
+ return HandlePacket_ILLFORMED ("Could not parse thread number in T packet");
+ }
+
+ nub_state_t state = DNBThreadGetState (m_ctx.ProcessID(), tid);
+ if (state == eStateInvalid || state == eStateExited || state == eStateCrashed)
+ {
+ return SendPacket ("E16");
+ }
+
+ return SendPacket ("OK");
+}
+
+
+rnb_err_t
+RNBRemote::HandlePacket_z (const char *p)
+{
+ if (p == NULL || *p == '\0')
+ return HandlePacket_ILLFORMED ("No thread specified in z packet");
+
+ if (!m_ctx.HasValidProcessID())
+ return SendPacket ("E15");
+
+ char packet_cmd = *p++;
+ char break_type = *p++;
+
+ if (*p++ != ',')
+ return HandlePacket_ILLFORMED ("Comma separator missing in z packet");
+
+ char *c = NULL;
+ nub_process_t pid = m_ctx.ProcessID();
+ errno = 0;
+ nub_addr_t addr = strtoull (p, &c, 16);
+ if (errno != 0 && addr == 0)
+ return HandlePacket_ILLFORMED ("Invalid address in z packet");
+ p = c;
+ if (*p++ != ',')
+ return HandlePacket_ILLFORMED ("Comma separator missing in z packet");
+
+ errno = 0;
+ uint32_t byte_size = strtoul (p, &c, 16);
+ if (errno != 0 && byte_size == 0)
+ return HandlePacket_ILLFORMED ("Invalid length in z packet");
+
+ if (packet_cmd == 'Z')
+ {
+ // set
+ switch (break_type)
+ {
+ case '0': // set software breakpoint
+ case '1': // set hardware breakpoint
+ {
+ // gdb can send multiple Z packets for the same address and
+ // these calls must be ref counted.
+ bool hardware = (break_type == '1');
+
+ // Check if we currently have a breakpoint already set at this address
+ BreakpointMapIter pos = m_breakpoints.find(addr);
+ if (pos != m_breakpoints.end())
+ {
+ // We do already have a breakpoint at this address, increment
+ // its reference count and return OK
+ pos->second.Retain();
+ return SendPacket ("OK");
+ }
+ else
+ {
+ // We do NOT already have a breakpoint at this address, So lets
+ // create one.
+ nub_break_t break_id = DNBBreakpointSet (pid, addr, byte_size, hardware);
+ if (break_id != INVALID_NUB_BREAK_ID)
+ {
+ // We successfully created a breakpoint, now lets full out
+ // a ref count structure with the breakID and add it to our
+ // map.
+ Breakpoint rnbBreakpoint(break_id);
+ m_breakpoints[addr] = rnbBreakpoint;
+ return SendPacket ("OK");
+ }
+ else
+ {
+ // We failed to set the software breakpoint
+ return SendPacket ("E09");
+ }
+ }
+ }
+ break;
+
+ case '2': // set write watchpoint
+ case '3': // set read watchpoint
+ case '4': // set access watchpoint
+ {
+ bool hardware = true;
+ uint32_t watch_flags = 0;
+ if (break_type == '2')
+ watch_flags = WATCH_TYPE_WRITE;
+ else if (break_type == '3')
+ watch_flags = WATCH_TYPE_READ;
+ else
+ watch_flags = WATCH_TYPE_READ | WATCH_TYPE_WRITE;
+
+ // Check if we currently have a watchpoint already set at this address
+ BreakpointMapIter pos = m_watchpoints.find(addr);
+ if (pos != m_watchpoints.end())
+ {
+ // We do already have a watchpoint at this address, increment
+ // its reference count and return OK
+ pos->second.Retain();
+ return SendPacket ("OK");
+ }
+ else
+ {
+ // We do NOT already have a breakpoint at this address, So lets
+ // create one.
+ nub_watch_t watch_id = DNBWatchpointSet (pid, addr, byte_size, watch_flags, hardware);
+ if (watch_id != INVALID_NUB_BREAK_ID)
+ {
+ // We successfully created a watchpoint, now lets full out
+ // a ref count structure with the watch_id and add it to our
+ // map.
+ Breakpoint rnbWatchpoint(watch_id);
+ m_watchpoints[addr] = rnbWatchpoint;
+ return SendPacket ("OK");
+ }
+ else
+ {
+ // We failed to set the watchpoint
+ return SendPacket ("E09");
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if (packet_cmd == 'z')
+ {
+ // remove
+ switch (break_type)
+ {
+ case '0': // remove software breakpoint
+ case '1': // remove hardware breakpoint
+ {
+ // gdb can send multiple z packets for the same address and
+ // these calls must be ref counted.
+ BreakpointMapIter pos = m_breakpoints.find(addr);
+ if (pos != m_breakpoints.end())
+ {
+ // We currently have a breakpoint at address ADDR. Decrement
+ // its reference count, and it that count is now zero we
+ // can clear the breakpoint.
+ pos->second.Release();
+ if (pos->second.RefCount() == 0)
+ {
+ if (DNBBreakpointClear (pid, pos->second.BreakID()))
+ {
+ m_breakpoints.erase(pos);
+ return SendPacket ("OK");
+ }
+ else
+ {
+ return SendPacket ("E08");
+ }
+ }
+ else
+ {
+ // We still have references to this breakpoint don't
+ // delete it, just decrementing the reference count
+ // is enough.
+ return SendPacket ("OK");
+ }
+ }
+ else
+ {
+ // We don't know about any breakpoints at this address
+ return SendPacket ("E08");
+ }
+ }
+ break;
+
+ case '2': // remove write watchpoint
+ case '3': // remove read watchpoint
+ case '4': // remove access watchpoint
+ {
+ // gdb can send multiple z packets for the same address and
+ // these calls must be ref counted.
+ BreakpointMapIter pos = m_watchpoints.find(addr);
+ if (pos != m_watchpoints.end())
+ {
+ // We currently have a watchpoint at address ADDR. Decrement
+ // its reference count, and it that count is now zero we
+ // can clear the watchpoint.
+ pos->second.Release();
+ if (pos->second.RefCount() == 0)
+ {
+ if (DNBWatchpointClear (pid, pos->second.BreakID()))
+ {
+ m_watchpoints.erase(pos);
+ return SendPacket ("OK");
+ }
+ else
+ {
+ return SendPacket ("E08");
+ }
+ }
+ else
+ {
+ // We still have references to this watchpoint don't
+ // delete it, just decrementing the reference count
+ // is enough.
+ return SendPacket ("OK");
+ }
+ }
+ else
+ {
+ // We don't know about any watchpoints at this address
+ return SendPacket ("E08");
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return HandlePacket_UNIMPLEMENTED(p);
+}
+
+/* `p XX'
+ print the contents of register X */
+
+rnb_err_t
+RNBRemote::HandlePacket_p (const char *p)
+{
+ if (p == NULL || *p == '\0')
+ {
+ return HandlePacket_ILLFORMED ("No thread specified in p packet");
+ }
+ if (!m_ctx.HasValidProcessID())
+ {
+ return SendPacket ("E15");
+ }
+ nub_process_t pid = m_ctx.ProcessID();
+ errno = 0;
+ uint32_t reg = strtoul (p + 1, NULL, 16);
+ if (errno != 0 && reg == 0)
+ {
+ return HandlePacket_ILLFORMED ("Could not parse thread number in p packet");
+ }
+
+ const register_map_entry_t *reg_entry;
+
+ if (reg < g_num_reg_entries)
+ reg_entry = &g_reg_entries[reg];
+ else
+ reg_entry = NULL;
+
+ std::ostringstream ostrm;
+ if (reg_entry == NULL)
+ {
+ DNBLogError("RNBRemote::HandlePacket_p(%s): unknown register number %u requested\n", p, reg);
+ ostrm << "00000000";
+ }
+ else if (reg_entry->nub_info.reg == -1)
+ {
+ if (reg_entry->gdb_size > 0)
+ {
+ if (reg_entry->fail_value != NULL)
+ {
+ append_hex_value(ostrm, reg_entry->fail_value, reg_entry->gdb_size, false);
+ }
+ else
+ {
+ std::basic_string<uint8_t> zeros(reg_entry->gdb_size, '\0');
+ append_hex_value(ostrm, zeros.data(), zeros.size(), false);
+ }
+ }
+ }
+ else
+ {
+ nub_thread_t tid = GetCurrentThread();
+ register_value_in_hex_fixed_width (ostrm, pid, tid, reg_entry);
+ }
+ return SendPacket (ostrm.str());
+}
+
+/* `Pnn=rrrrr'
+ Set register number n to value r.
+ n and r are hex strings. */
+
+rnb_err_t
+RNBRemote::HandlePacket_P (const char *p)
+{
+ if (p == NULL || *p == '\0')
+ {
+ return HandlePacket_ILLFORMED ("Empty P packet");
+ }
+ if (!m_ctx.HasValidProcessID())
+ {
+ return SendPacket ("E28");
+ }
+
+ nub_process_t pid = m_ctx.ProcessID();
+
+ StringExtractor packet (p);
+
+ const char cmd_char = packet.GetChar();
+ // Register ID is always in big endian
+ const uint32_t reg = packet.GetHexMaxU32 (false, UINT32_MAX);
+ const char equal_char = packet.GetChar();
+
+ if (cmd_char != 'P')
+ return HandlePacket_ILLFORMED ("Improperly formed P packet");
+
+ if (reg == UINT32_MAX)
+ return SendPacket ("E29");
+
+ if (equal_char != '=')
+ return SendPacket ("E30");
+
+ const register_map_entry_t *reg_entry;
+
+ if (reg >= g_num_reg_entries)
+ return SendPacket("E47");
+
+ reg_entry = &g_reg_entries[reg];
+
+ if (reg_entry->nub_info.set == -1 && reg_entry->nub_info.reg == -1)
+ {
+ DNBLogError("RNBRemote::HandlePacket_P(%s): unknown register number %u requested\n", p, reg);
+ return SendPacket("E48");
+ }
+
+ DNBRegisterValue reg_value;
+ reg_value.info = reg_entry->nub_info;
+ packet.GetHexBytes (reg_value.value.v_sint8, reg_entry->gdb_size, 0xcc);
+
+ nub_thread_t tid;
+ tid = GetCurrentThread ();
+
+ if (!DNBThreadSetRegisterValueByID (pid, tid, reg_entry->nub_info.set, reg_entry->nub_info.reg, &reg_value))
+ {
+ return SendPacket ("E32");
+ }
+ return SendPacket ("OK");
+}
+
+/* `c [addr]'
+ Continue, optionally from a specified address. */
+
+rnb_err_t
+RNBRemote::HandlePacket_c (const char *p)
+{
+ const nub_process_t pid = m_ctx.ProcessID();
+
+ if (pid == INVALID_NUB_PROCESS)
+ return SendPacket ("E23");
+
+ DNBThreadResumeAction action = { INVALID_NUB_THREAD, eStateRunning, 0, INVALID_NUB_ADDRESS };
+
+ if (*(p + 1) != '\0')
+ {
+ action.tid = GetContinueThread();
+ errno = 0;
+ action.addr = strtoull (p + 1, NULL, 16);
+ if (errno != 0 && action.addr == 0)
+ return HandlePacket_ILLFORMED ("Could not parse address in c packet");
+ }
+
+ DNBThreadResumeActions thread_actions;
+ thread_actions.Append(action);
+ thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0);
+ if (!DNBProcessResume (pid, thread_actions.GetFirst(), thread_actions.GetSize()))
+ return SendPacket ("E25");
+ // Don't send an "OK" packet; response is the stopped/exited message.
+ return rnb_success;
+}
+
+/* `C sig [;addr]'
+ Resume with signal sig, optionally at address addr. */
+
+rnb_err_t
+RNBRemote::HandlePacket_C (const char *p)
+{
+ const nub_process_t pid = m_ctx.ProcessID();
+
+ if (pid == INVALID_NUB_PROCESS)
+ return SendPacket ("E36");
+
+ DNBThreadResumeAction action = { INVALID_NUB_THREAD, eStateRunning, 0, INVALID_NUB_ADDRESS };
+ int process_signo = -1;
+ if (*(p + 1) != '\0')
+ {
+ action.tid = GetContinueThread();
+ char *end = NULL;
+ errno = 0;
+ process_signo = strtoul (p + 1, &end, 16);
+ if (errno != 0)
+ return HandlePacket_ILLFORMED ("Could not parse signal in C packet");
+ else if (*end == ';')
+ {
+ errno = 0;
+ action.addr = strtoull (end + 1, NULL, 16);
+ if (errno != 0 && action.addr == 0)
+ return HandlePacket_ILLFORMED ("Could not parse address in C packet");
+ }
+ }
+
+ DNBThreadResumeActions thread_actions;
+ thread_actions.Append (action);
+ thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, action.signal);
+ if (!DNBProcessSignal(pid, process_signo))
+ return SendPacket ("E52");
+ if (!DNBProcessResume (pid, thread_actions.GetFirst(), thread_actions.GetSize()))
+ return SendPacket ("E38");
+ /* Don't send an "OK" packet; response is the stopped/exited message. */
+ return rnb_success;
+}
+
+//----------------------------------------------------------------------
+// 'D' packet
+// Detach from gdb.
+//----------------------------------------------------------------------
+rnb_err_t
+RNBRemote::HandlePacket_D (const char *p)
+{
+ SendPacket ("OK");
+ if (m_ctx.HasValidProcessID())
+ DNBProcessDetach(m_ctx.ProcessID());
+ return rnb_success;
+}
+
+/* `k'
+ Kill the inferior process. */
+
+rnb_err_t
+RNBRemote::HandlePacket_k (const char *p)
+{
+ if (!m_ctx.HasValidProcessID())
+ return SendPacket ("E26");
+ if (!DNBProcessKill (m_ctx.ProcessID()))
+ return SendPacket ("E27");
+ return SendPacket ("OK");
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_stop_process (const char *p)
+{
+ DNBProcessSignal (m_ctx.ProcessID(), SIGSTOP);
+ //DNBProcessSignal (m_ctx.ProcessID(), SIGINT);
+ // Do not send any response packet! Wait for the stop reply packet to naturally happen
+ return rnb_success;
+}
+
+/* `s'
+ Step the inferior process. */
+
+rnb_err_t
+RNBRemote::HandlePacket_s (const char *p)
+{
+ const nub_process_t pid = m_ctx.ProcessID();
+ if (pid == INVALID_NUB_PROCESS)
+ return SendPacket ("E32");
+
+ // Hardware supported stepping not supported on arm
+ nub_thread_t tid = GetContinueThread ();
+ if (tid == 0 || tid == -1)
+ tid = GetCurrentThread();
+
+ if (tid == INVALID_NUB_THREAD)
+ return SendPacket ("E33");
+
+ DNBThreadResumeActions thread_actions;
+ thread_actions.AppendAction(tid, eStateStepping);
+
+ // Make all other threads stop when we are stepping
+ thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0);
+ if (!DNBProcessResume (pid, thread_actions.GetFirst(), thread_actions.GetSize()))
+ return SendPacket ("E49");
+ // Don't send an "OK" packet; response is the stopped/exited message.
+ return rnb_success;
+}
+
+/* `S sig [;addr]'
+ Step with signal sig, optionally at address addr. */
+
+rnb_err_t
+RNBRemote::HandlePacket_S (const char *p)
+{
+ const nub_process_t pid = m_ctx.ProcessID();
+ if (pid == INVALID_NUB_PROCESS)
+ return SendPacket ("E36");
+
+ DNBThreadResumeAction action = { INVALID_NUB_THREAD, eStateStepping, 0, INVALID_NUB_ADDRESS };
+
+ if (*(p + 1) != '\0')
+ {
+ char *end = NULL;
+ errno = 0;
+ action.signal = strtoul (p + 1, &end, 16);
+ if (errno != 0)
+ return HandlePacket_ILLFORMED ("Could not parse signal in S packet");
+ else if (*end == ';')
+ {
+ errno = 0;
+ action.addr = strtoull (end + 1, NULL, 16);
+ if (errno != 0 && action.addr == 0)
+ {
+ return HandlePacket_ILLFORMED ("Could not parse address in S packet");
+ }
+ }
+ }
+
+ action.tid = GetContinueThread ();
+ if (action.tid == 0 || action.tid == -1)
+ return SendPacket ("E40");
+
+ nub_state_t tstate = DNBThreadGetState (pid, action.tid);
+ if (tstate == eStateInvalid || tstate == eStateExited)
+ return SendPacket ("E37");
+
+
+ DNBThreadResumeActions thread_actions;
+ thread_actions.Append (action);
+
+ // Make all other threads stop when we are stepping
+ thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
+ if (!DNBProcessResume (pid, thread_actions.GetFirst(), thread_actions.GetSize()))
+ return SendPacket ("E39");
+
+ // Don't send an "OK" packet; response is the stopped/exited message.
+ return rnb_success;
+}
+
+rnb_err_t
+RNBRemote::HandlePacket_qHostInfo (const char *p)
+{
+ std::ostringstream strm;
+
+ uint32_t cputype, is_64_bit_capable;
+ size_t len = sizeof(cputype);
+ bool promoted_to_64 = false;
+ if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0)
+ {
+ len = sizeof (is_64_bit_capable);
+ if (::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0) == 0)
+ {
+ if (is_64_bit_capable && ((cputype & CPU_ARCH_ABI64) == 0))
+ {
+ promoted_to_64 = true;
+ cputype |= CPU_ARCH_ABI64;
+ }
+ }
+
+ strm << "cputype:" << std::dec << cputype << ';';
+ }
+
+ uint32_t cpusubtype;
+ len = sizeof(cpusubtype);
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
+ {
+ if (promoted_to_64 &&
+ cputype == CPU_TYPE_X86_64 &&
+ cpusubtype == CPU_SUBTYPE_486)
+ cpusubtype = CPU_SUBTYPE_X86_64_ALL;
+
+ strm << "cpusubtype:" << std::dec << cpusubtype << ';';
+ }
+
+ char ostype[64];
+ len = sizeof(ostype);
+ if (::sysctlbyname("kern.ostype", &ostype, &len, NULL, 0) == 0)
+ strm << "ostype:" << std::dec << ostype << ';';
+
+ strm << "vendor:apple;";
+
+#if defined (__LITTLE_ENDIAN__)
+ strm << "endian:little;";
+#elif defined (__BIG_ENDIAN__)
+ strm << "endian:big;";
+#elif defined (__PDP_ENDIAN__)
+ strm << "endian:pdp;";
+#endif
+
+ strm << "ptrsize:" << std::dec << sizeof(void *) << ';';
+ return SendPacket (strm.str());
+}
+
diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h
new file mode 100644
index 00000000000..bec9d1812d0
--- /dev/null
+++ b/lldb/tools/debugserver/source/RNBRemote.h
@@ -0,0 +1,309 @@
+//===-- RNBRemote.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 12/12/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __RNBRemote_h__
+#define __RNBRemote_h__
+
+#include "RNBDefs.h"
+#include "DNB.h"
+#include "RNBContext.h"
+#include "RNBSocket.h"
+#include "PThreadMutex.h"
+#include <string>
+#include <vector>
+#include <deque>
+#include <map>
+
+class RNBSocket;
+class RNBContext;
+class PThreadEvents;
+
+enum event_loop_mode { debug_nub, gdb_remote_protocol, done };
+
+class RNBRemote
+{
+public:
+
+ typedef enum {
+ invalid_packet = 0,
+ ack, // '+'
+ nack, // '-'
+ halt, // ^C (async halt)
+ use_extended_mode, // '!'
+ why_halted, // '?'
+ set_argv, // 'A'
+ set_bp, // 'B'
+ cont, // 'c'
+ continue_with_sig, // 'C'
+ detach, // 'D'
+ read_general_regs, // 'g'
+ write_general_regs, // 'G'
+ set_thread, // 'H'
+ step_inferior_one_cycle, // 'i'
+ signal_and_step_inf_one_cycle, // 'I'
+ kill, // 'k'
+ read_memory, // 'm'
+ write_memory, // 'M'
+ read_register, // 'p'
+ write_register, // 'P'
+ restart, // 'R'
+ single_step, // 's'
+ single_step_with_sig, // 'S'
+ search_mem_backwards, // 't'
+ thread_alive_p, // 'T'
+ vattach, // 'vAttach'
+ vattachwait, // 'vAttachWait'
+ vcont, // 'vCont'
+ vcont_list_actions, // 'vCont?'
+ write_data_to_memory, // 'X'
+ insert_mem_bp, // 'Z0'
+ remove_mem_bp, // 'z0'
+ insert_hardware_bp, // 'Z1'
+ remove_hardware_bp, // 'z1'
+ insert_write_watch_bp, // 'Z2'
+ remove_write_watch_bp, // 'z2'
+ insert_read_watch_bp, // 'Z3'
+ remove_read_watch_bp, // 'z3'
+ insert_access_watch_bp, // 'Z4'
+ remove_access_watch_bp, // 'z4'
+
+ query_current_thread_id, // 'qC'
+ query_memory_crc, // 'qCRC:'
+ query_thread_ids_first, // 'qfThreadInfo'
+ query_thread_ids_subsequent, // 'qsThreadInfo'
+ query_thread_extra_info, // 'qThreadExtraInfo'
+ query_thread_stop_info, // 'qThreadStopInfo'
+ query_image_offsets, // 'qOffsets'
+ query_symbol_lookup, // 'gSymbols'
+ query_launch_success, // 'qLaunchSuccess'
+ query_register_info, // 'qRegisterInfo'
+ query_shlib_notify_info_addr, // 'qShlibInfoAddr'
+ query_step_packet_supported, // 'qStepPacketSupported'
+ query_host_info, // 'qHostInfo'
+ pass_signals_to_inferior, // 'QPassSignals'
+ start_noack_mode, // 'QStartNoAckMode'
+ set_logging_mode, // 'QSetLogging:'
+ set_max_packet_size, // 'QSetMaxPacketSize:'
+ set_max_payload_size, // 'QSetMaxPayloadSize:'
+ set_environment_variable, // 'QEnvironment:'
+ allocate_memory, // '_M'
+ deallocate_memory, // '_m'
+
+ unknown_type,
+ } PacketEnum;
+
+ typedef rnb_err_t (RNBRemote::*HandlePacketCallback)(const char *p);
+
+ RNBRemote(bool use_native_regs);
+ ~RNBRemote();
+
+ static void InitializeRegisters (int use_native);
+
+ rnb_err_t HandleAsyncPacket(PacketEnum *type = NULL);
+ rnb_err_t HandleReceivedPacket(PacketEnum *type = NULL);
+
+ nub_thread_t GetContinueThread () const
+ {
+ return m_continue_thread;
+ }
+
+ void SetContinueThread (nub_thread_t tid)
+ {
+ m_continue_thread = tid;
+ }
+
+ nub_thread_t GetCurrentThread () const
+ {
+ if (m_thread == 0 || m_thread == -1)
+ return DNBProcessGetCurrentThread (m_ctx.ProcessID());
+ return m_thread;
+ }
+
+ void SetCurrentThread (nub_thread_t tid)
+ {
+ DNBProcessSetCurrentThread (m_ctx.ProcessID(), tid);
+ m_thread = tid;
+ }
+
+ static void* ThreadFunctionReadRemoteData(void *arg);
+ void StartReadRemoteDataThread ();
+ void StopReadRemoteDataThread ();
+
+ void NotifyThatProcessStopped (void);
+
+ rnb_err_t HandlePacket_A (const char *p);
+ rnb_err_t HandlePacket_H (const char *p);
+ rnb_err_t HandlePacket_qC (const char *p);
+ rnb_err_t HandlePacket_qLaunchSuccess (const char *p);
+ rnb_err_t HandlePacket_qRegisterInfo (const char *p);
+ rnb_err_t HandlePacket_qShlibInfoAddr (const char *p);
+ rnb_err_t HandlePacket_qStepPacketSupported (const char *p);
+ rnb_err_t HandlePacket_qThreadInfo (const char *p);
+ rnb_err_t HandlePacket_qThreadExtraInfo (const char *p);
+ rnb_err_t HandlePacket_qThreadStopInfo (const char *p);
+ rnb_err_t HandlePacket_qHostInfo (const char *p);
+ rnb_err_t HandlePacket_Q (const char *p);
+ rnb_err_t HandlePacket_last_signal (const char *p);
+ rnb_err_t HandlePacket_m (const char *p);
+ rnb_err_t HandlePacket_M (const char *p);
+ rnb_err_t HandlePacket_X (const char *p);
+ rnb_err_t HandlePacket_g (const char *p);
+ rnb_err_t HandlePacket_G (const char *p);
+ rnb_err_t HandlePacket_z (const char *p);
+ rnb_err_t HandlePacket_T (const char *p);
+ rnb_err_t HandlePacket_p (const char *p);
+ rnb_err_t HandlePacket_P (const char *p);
+ rnb_err_t HandlePacket_c (const char *p);
+ rnb_err_t HandlePacket_C (const char *p);
+ rnb_err_t HandlePacket_D (const char *p);
+ rnb_err_t HandlePacket_k (const char *p);
+ rnb_err_t HandlePacket_s (const char *p);
+ rnb_err_t HandlePacket_S (const char *p);
+ rnb_err_t HandlePacket_v (const char *p);
+ rnb_err_t HandlePacket_UNIMPLEMENTED (const char *p);
+ rnb_err_t HandlePacket_ILLFORMED (const char *description);
+ rnb_err_t HandlePacket_AllocateMemory (const char *p);
+ rnb_err_t HandlePacket_DeallocateMemory (const char *p);
+
+ rnb_err_t HandlePacket_stop_process (const char *p);
+
+ rnb_err_t SendStopReplyPacketForThread (nub_thread_t tid);
+ rnb_err_t SendHexEncodedBytePacket (const char *header, const void *buf, size_t buf_len, const char *footer);
+ rnb_err_t SendSTDOUTPacket (char *buf, nub_size_t buf_size);
+ rnb_err_t SendSTDERRPacket (char *buf, nub_size_t buf_size);
+ void FlushSTDIO ();
+
+ RNBContext& Context() { return m_ctx; }
+ RNBSocket& Comm() { return m_comm; }
+
+private:
+ // Outlaw some contructors
+ RNBRemote (const RNBRemote &);
+
+protected:
+
+ static void
+ InitializeNativeRegisters ();
+
+ rnb_err_t GetCommData ();
+ void CommDataReceived(const std::string& data);
+ struct Packet
+ {
+ typedef std::vector<Packet> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ PacketEnum type;
+ HandlePacketCallback normal; // Function to call when inferior is halted
+ HandlePacketCallback async; // Function to call when inferior is running
+ std::string abbrev;
+ std::string printable_name;
+ Packet() :
+ type(invalid_packet),
+ normal (NULL),
+ async (NULL),
+ abbrev (),
+ printable_name ()
+ {
+ }
+
+ Packet( PacketEnum in_type,
+ HandlePacketCallback in_normal,
+ HandlePacketCallback in_async,
+ const char *in_abbrev,
+ const char *in_printable_name) :
+ type (in_type),
+ normal (in_normal),
+ async (in_async),
+ abbrev (in_abbrev),
+ printable_name (in_printable_name)
+ {
+ }
+ };
+
+ rnb_err_t GetPacket (std::string &packet_data, RNBRemote::Packet& packet_info, bool wait);
+ rnb_err_t SendPacket (const std::string &);
+
+ void CreatePacketTable ();
+ rnb_err_t GetPacketPayload (std::string &);
+
+ // gdb can send multiple Z/z packets for the same address and
+ // these calls must be ref counted.
+ typedef struct Breakpoint
+ {
+ Breakpoint(nub_break_t breakID) :
+ m_breakID(breakID),
+ m_refCount(1)
+ {
+ }
+
+ Breakpoint() :
+ m_breakID(INVALID_NUB_BREAK_ID),
+ m_refCount(0)
+ {
+ }
+
+ Breakpoint(const Breakpoint& rhs) :
+ m_breakID(rhs.m_breakID),
+ m_refCount(rhs.m_refCount)
+ {
+ }
+
+ nub_break_t BreakID() const { return m_breakID; }
+ uint32_t RefCount() const { return m_refCount; }
+ void Release() { if (m_refCount > 0) --m_refCount; }
+ void Retain() { ++m_refCount; }
+
+ nub_break_t m_breakID;
+ uint32_t m_refCount;
+ };
+ typedef std::map<nub_addr_t, Breakpoint> BreakpointMap;
+ typedef BreakpointMap::iterator BreakpointMapIter;
+ typedef BreakpointMap::const_iterator BreakpointMapConstIter;
+ RNBContext m_ctx; // process context
+ RNBSocket m_comm; // communication port
+ bool m_extended_mode; // are we in extended mode?
+ bool m_noack_mode; // are we in no-ack mode?
+ nub_thread_t m_continue_thread; // thread to continue; 0 for any, -1 for all
+ nub_thread_t m_thread; // thread for other ops; 0 for any, -1 for all
+ PThreadMutex m_mutex; // Mutex that protects
+ uint32_t m_packets_recvd;
+ Packet::collection m_packets;
+ std::deque<std::string> m_rx_packets;
+ std::string m_rx_partial_data; // For packets that may come in more than one batch, anything left over can be left here
+ pthread_t m_rx_pthread;
+ BreakpointMap m_breakpoints;
+ BreakpointMap m_watchpoints;
+ uint32_t m_max_payload_size; // the maximum sized payload we should send to gdb
+ bool m_use_native_regs;
+};
+
+/* We translate the /usr/include/mach/exception_types.h exception types
+ (e.g. EXC_BAD_ACCESS) to the fake BSD signal numbers that gdb uses
+ in include/gdb/signals.h (e.g. TARGET_EXC_BAD_ACCESS). These hard
+ coded values for TARGET_EXC_BAD_ACCESS et al must match the gdb
+ values in its include/gdb/signals.h. */
+
+#define TARGET_EXC_BAD_ACCESS 0x91
+#define TARGET_EXC_BAD_INSTRUCTION 0x92
+#define TARGET_EXC_ARITHMETIC 0x93
+#define TARGET_EXC_EMULATION 0x94
+#define TARGET_EXC_SOFTWARE 0x95
+#define TARGET_EXC_BREAKPOINT 0x96
+
+/* Generally speaking, you can't assume gdb can receive more than 399 bytes
+ at a time with a random gdb. This bufsize constant is only specifying
+ how many bytes gdb can *receive* from debugserver -- it tells us nothing
+ about how many bytes gdb might try to send in a single packet. */
+#define DEFAULT_GDB_REMOTE_PROTOCOL_BUFSIZE 399
+
+#endif // #ifndef __RNBRemote_h__
diff --git a/lldb/tools/debugserver/source/RNBServices.cpp b/lldb/tools/debugserver/source/RNBServices.cpp
new file mode 100644
index 00000000000..1fe791d37be
--- /dev/null
+++ b/lldb/tools/debugserver/source/RNBServices.cpp
@@ -0,0 +1,145 @@
+//===-- RNBServices.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Christopher Friesen on 3/21/08.
+//
+//===----------------------------------------------------------------------===//
+
+#import "RNBServices.h"
+
+#import <CoreFoundation/CoreFoundation.h>
+#import <unistd.h>
+#import "DNBLog.h"
+
+#if defined (__arm__)
+#import <SpringBoardServices/SpringBoardServices.h>
+#endif
+
+int
+ListApplications(std::string& plist, bool opt_runningApps, bool opt_debuggable)
+{
+#if defined (__arm__)
+ int result = -1;
+
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+
+ // Create a mutable array that we can populate. Specify zero so it can be of any size.
+ CFReleaser<CFMutableArrayRef> plistMutableArray (::CFArrayCreateMutable (alloc, 0, &kCFTypeArrayCallBacks));
+
+ CFReleaser<CFStringRef> sbsFrontAppID (::SBSCopyFrontmostApplicationDisplayIdentifier ());
+ CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable));
+
+ CFIndex count = ::CFArrayGetCount (sbsAppIDs.get());
+ CFIndex i = 0;
+ for (i = 0; i < count; i++)
+ {
+ CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i);
+
+ // Create a new mutable dictionary for each application
+ CFReleaser<CFMutableDictionaryRef> appInfoDict (::CFDictionaryCreateMutable (alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+
+ // Get the process id for the app (if there is one)
+ pid_t pid = INVALID_NUB_PROCESS;
+ if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &pid) == true)
+ {
+ CFReleaser<CFNumberRef> pidCFNumber (::CFNumberCreate (alloc, kCFNumberSInt32Type, &pid));
+ ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PID_KEY, pidCFNumber.get());
+ }
+
+ // Set the a boolean to indicate if this is the front most
+ if (sbsFrontAppID.get() && displayIdentifier && (::CFStringCompare (sbsFrontAppID.get(), displayIdentifier, 0) == kCFCompareEqualTo))
+ ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, kCFBooleanTrue);
+ else
+ ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, kCFBooleanFalse);
+
+
+ CFReleaser<CFStringRef> executablePath (::SBSCopyExecutablePathForDisplayIdentifier (displayIdentifier));
+ if (executablePath.get() != NULL)
+ {
+ ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PATH_KEY, executablePath.get());
+ }
+
+ CFReleaser<CFStringRef> iconImagePath (::SBSCopyIconImagePathForDisplayIdentifier (displayIdentifier)) ;
+ if (iconImagePath.get() != NULL)
+ {
+ ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_ICON_PATH_KEY, iconImagePath.get());
+ }
+
+ CFReleaser<CFStringRef> localizedDisplayName (::SBSCopyLocalizedApplicationNameForDisplayIdentifier (displayIdentifier));
+ if (localizedDisplayName.get() != NULL)
+ {
+ ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_DISPLAY_NAME_KEY, localizedDisplayName.get());
+ }
+
+ // Append the application info to the plist array
+ ::CFArrayAppendValue (plistMutableArray.get(), appInfoDict.get());
+ }
+
+ CFReleaser<CFDataRef> plistData (::CFPropertyListCreateXMLData (alloc, plistMutableArray.get()));
+
+ // write plist to service port
+ if (plistData.get() != NULL)
+ {
+ CFIndex size = ::CFDataGetLength (plistData.get());
+ const UInt8 *bytes = ::CFDataGetBytePtr (plistData.get());
+ if (bytes != NULL && size > 0)
+ {
+ plist.assign((char *)bytes, size);
+ return 0; // Success
+ }
+ else
+ {
+ DNBLogError("empty application property list.");
+ result = -2;
+ }
+ }
+ else
+ {
+ DNBLogError("serializing task list.");
+ result = -3;
+ }
+
+ return result;
+#else
+ // TODO: list all current processes
+ DNBLogError("SBS doesn't support getting application list.");
+ return -1;
+#endif
+}
+
+
+bool
+IsSBProcess (nub_process_t pid)
+{
+#if defined (__arm__)
+ bool opt_runningApps = true;
+ bool opt_debuggable = false;
+
+ CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable));
+ if (sbsAppIDs.get() != NULL)
+ {
+ CFIndex count = ::CFArrayGetCount (sbsAppIDs.get());
+ CFIndex i = 0;
+ for (i = 0; i < count; i++)
+ {
+ CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i);
+
+ // Get the process id for the app (if there is one)
+ pid_t sbs_pid = INVALID_NUB_PROCESS;
+ if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &sbs_pid) == TRUE)
+ {
+ if (sbs_pid == pid)
+ return true;
+ }
+ }
+ }
+#endif
+ return false;
+}
+
diff --git a/lldb/tools/debugserver/source/RNBServices.h b/lldb/tools/debugserver/source/RNBServices.h
new file mode 100644
index 00000000000..0164e33b0bf
--- /dev/null
+++ b/lldb/tools/debugserver/source/RNBServices.h
@@ -0,0 +1,29 @@
+//===-- RNBServices.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Christopher Friesen on 3/21/08.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __RNBServices_h__
+#define __RNBServices_h__
+
+#include <string>
+#include "RNBDefs.h"
+
+#define DTSERVICES_APP_FRONTMOST_KEY CFSTR("isFrontApp")
+#define DTSERVICES_APP_PATH_KEY CFSTR("executablePath")
+#define DTSERVICES_APP_ICON_PATH_KEY CFSTR("iconPath")
+#define DTSERVICES_APP_DISPLAY_NAME_KEY CFSTR("displayName")
+#define DTSERVICES_APP_PID_KEY CFSTR("pid")
+
+int ListApplications (std::string &plist, bool opt_runningApps, bool opt_debuggable);
+bool IsSBProcess (nub_process_t pid);
+
+#endif // __RNBServices_h__
diff --git a/lldb/tools/debugserver/source/RNBSocket.cpp b/lldb/tools/debugserver/source/RNBSocket.cpp
new file mode 100644
index 00000000000..08fa4ac79ce
--- /dev/null
+++ b/lldb/tools/debugserver/source/RNBSocket.cpp
@@ -0,0 +1,251 @@
+//===-- RNBSocket.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 12/12/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RNBSocket.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <termios.h>
+#include "DNBLog.h"
+#include "DNBError.h"
+
+#if defined (__arm__)
+#include "lockdown.h"
+#endif
+
+/* Once we have a RNBSocket object with a port # specified,
+ this function is called to wait for an incoming connection.
+ This function blocks while waiting for that connection. */
+
+rnb_err_t
+RNBSocket::Listen (in_port_t listen_port_num)
+{
+ //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
+ // Disconnect without saving errno
+ Disconnect (false);
+
+ DNBError err;
+ int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (listen_port == -1)
+ err.SetError(errno, DNBError::POSIX);
+
+ if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
+ err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol = IPPROTO_TCP ) => socket = %i", listen_port);
+
+ if (err.Fail())
+ return rnb_err;
+
+ // enable local address reuse
+ SetSocketOption (listen_port, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ struct sockaddr_in sa;
+ ::memset (&sa, 0, sizeof sa);
+ sa.sin_len = sizeof sa;
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons (listen_port_num);
+ sa.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ int error = ::bind (listen_port, (struct sockaddr *) &sa, sizeof(sa));
+ if (error == -1)
+ err.SetError(errno, DNBError::POSIX);
+
+ if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
+ err.LogThreaded("::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )", listen_port);
+
+ if (err.Fail())
+ {
+ ClosePort (listen_port, false);
+ return rnb_err;
+ }
+
+ error = ::listen (listen_port, 1);
+ if (error == -1)
+ err.SetError(errno, DNBError::POSIX);
+
+ if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
+ err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_port);
+
+ if (err.Fail())
+ {
+ ClosePort (listen_port, false);
+ return rnb_err;
+ }
+
+ m_conn_port = ::accept (listen_port, NULL, 0);
+ if (m_conn_port == -1)
+ err.SetError(errno, DNBError::POSIX);
+
+ if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
+ err.LogThreaded("::accept ( socket = %i, address = NULL, address_len = 0 )", listen_port);
+
+ if (err.Fail())
+ {
+ ClosePort (listen_port, false);
+ return rnb_err;
+ }
+ else
+ {
+ // We are done with the listen port
+ ClosePort (listen_port, false);
+
+ // Keep our TCP packets coming without any delays.
+ SetSocketOption (m_conn_port, IPPROTO_TCP, TCP_NODELAY, 1);
+ }
+
+ return rnb_success;
+}
+
+#if defined (__arm__)
+rnb_err_t
+RNBSocket::ConnectToService()
+{
+ DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME);
+ // Disconnect from any previous connections
+ Disconnect(false);
+
+ m_conn_port = ::lockdown_checkin (NULL, NULL);
+ if (m_conn_port == -1)
+ {
+ DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_checkin(NULL, NULL) failed");
+ return rnb_not_connected;
+ }
+ m_conn_port_from_lockdown = true;
+ return rnb_success;
+}
+#endif
+
+rnb_err_t
+RNBSocket::OpenFile (const char *path)
+{
+ DNBError err;
+ m_conn_port = open (path, O_RDWR);
+ if (m_conn_port == -1)
+ {
+ err.SetError(errno, DNBError::POSIX);
+ err.LogThreaded ("can't open file '%s'", path);
+ return rnb_not_connected;
+ }
+ else
+ {
+ struct termios stdin_termios;
+
+ if (::tcgetattr (m_conn_port, &stdin_termios) == 0)
+ {
+ stdin_termios.c_lflag &= ~ECHO; // Turn off echoing
+ stdin_termios.c_lflag &= ~ICANON; // Get one char at a time
+ ::tcsetattr (m_conn_port, TCSANOW, &stdin_termios);
+ }
+ }
+ return rnb_success;
+}
+
+int
+RNBSocket::SetSocketOption(int fd, int level, int option_name, int option_value)
+{
+ return ::setsockopt(fd, level, option_name, &option_value, sizeof(option_value));
+}
+
+rnb_err_t
+RNBSocket::Disconnect (bool save_errno)
+{
+ if (m_conn_port_from_lockdown)
+ m_conn_port_from_lockdown = false;
+ return ClosePort (m_conn_port, save_errno);
+}
+
+
+rnb_err_t
+RNBSocket::Read (std::string &p)
+{
+ char buf[1024];
+ p.clear();
+
+ // Note that BUF is on the stack so we must be careful to keep any
+ // writes to BUF from overflowing or we'll have security issues.
+
+ if (m_conn_port == -1)
+ return rnb_err;
+
+ //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
+ DNBError err;
+ int bytesread = read (m_conn_port, buf, sizeof (buf));
+ if (bytesread <= 0)
+ err.SetError(errno, DNBError::POSIX);
+ else
+ p.append(buf, bytesread);
+
+ if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
+ err.LogThreaded("::read ( %i, %p, %zu ) => %i", m_conn_port, buf, sizeof (buf), bytesread);
+
+ // Our port went away - we have to mark this so IsConnected will return the truth.
+ if (bytesread == 0)
+ {
+ m_conn_port = -1;
+ return rnb_not_connected;
+ }
+ else if (bytesread == -1)
+ {
+ m_conn_port = -1;
+ return rnb_err;
+ }
+ // Strip spaces from the end of the buffer
+ while (!p.empty() && isspace (p[p.size() - 1]))
+ p.erase (p.size () - 1);
+
+ // Most data in the debugserver packets valid printable characters...
+ DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str());
+ return rnb_success;
+}
+
+rnb_err_t
+RNBSocket::Write (const void *buffer, size_t length)
+{
+ if (m_conn_port == -1)
+ return rnb_err;
+
+ DNBError err;
+ int bytessent = send (m_conn_port, buffer, length, 0);
+ if (bytessent < 0)
+ err.SetError(errno, DNBError::POSIX);
+
+ if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
+ err.LogThreaded("::send ( socket = %i, buffer = %p, length = %zu, flags = 0 ) => %i", m_conn_port, buffer, length, bytessent);
+
+ if (bytessent < 0)
+ return rnb_err;
+
+ if (bytessent != length)
+ return rnb_err;
+
+ DNBLogThreadedIf(LOG_RNB_PACKETS, "putpkt: %*s", length, (char *)buffer); // All data is string based in debugserver, so this is safe
+ DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", length, (char *)buffer);
+
+ return rnb_success;
+}
+
+
+rnb_err_t
+RNBSocket::ClosePort (int& fd, bool save_errno)
+{
+ int close_err = 0;
+ if (fd > 0)
+ {
+ errno = 0;
+ close_err = close (fd);
+ fd = -1;
+ }
+ return close_err != 0 ? rnb_err : rnb_success;
+}
+
+
diff --git a/lldb/tools/debugserver/source/RNBSocket.h b/lldb/tools/debugserver/source/RNBSocket.h
new file mode 100644
index 00000000000..de3db806ded
--- /dev/null
+++ b/lldb/tools/debugserver/source/RNBSocket.h
@@ -0,0 +1,65 @@
+//===-- RNBSocket.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 12/12/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __RNBSocket_h__
+#define __RNBSocket_h__
+
+#include "RNBDefs.h"
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <string>
+#include "DNBTimer.h"
+
+class RNBSocket
+{
+public:
+
+ RNBSocket () :
+ m_conn_port (-1),
+ m_conn_port_from_lockdown (false),
+ m_timer (true) // Make a thread safe timer
+ {
+ }
+ ~RNBSocket (void)
+ {
+ Disconnect (false);
+ }
+
+ rnb_err_t Listen (in_port_t listen_port_num);
+#if defined (__arm__)
+ rnb_err_t ConnectToService();
+#endif
+ rnb_err_t OpenFile (const char *path);
+ rnb_err_t Disconnect (bool save_errno);
+ rnb_err_t Read (std::string &p);
+ rnb_err_t Write (const void *buffer, size_t length);
+
+ bool IsConnected () const { return m_conn_port != -1; }
+ void SaveErrno (int curr_errno);
+ DNBTimer& Timer() { return m_timer; }
+
+ static int SetSocketOption(int fd, int level, int option_name, int option_value);
+private:
+ // Outlaw some constructors
+ RNBSocket (const RNBSocket &);
+
+protected:
+ rnb_err_t ClosePort (int& fd, bool save_errno);
+
+ int m_conn_port; // Socket we use to communicate once conn established
+ bool m_conn_port_from_lockdown;
+ DNBTimer m_timer;
+};
+
+
+#endif // #ifndef __RNBSocket_h__
diff --git a/lldb/tools/debugserver/source/SysSignal.cpp b/lldb/tools/debugserver/source/SysSignal.cpp
new file mode 100644
index 00000000000..69f34ed605c
--- /dev/null
+++ b/lldb/tools/debugserver/source/SysSignal.cpp
@@ -0,0 +1,66 @@
+//===-- SysSignal.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/18/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SysSignal.h"
+#include <signal.h>
+#include <stddef.h>
+
+const char *
+SysSignal::Name(int signal)
+{
+ switch (signal)
+ {
+ 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)
+ case SIGPOLL: return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported)
+#else // !_POSIX_C_SOURCE
+ case SIGEMT: return "SIGEMT"; // 7 EMT instruction
+#endif // !_POSIX_C_SOURCE
+ 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;
+}
diff --git a/lldb/tools/debugserver/source/SysSignal.h b/lldb/tools/debugserver/source/SysSignal.h
new file mode 100644
index 00000000000..438d137f310
--- /dev/null
+++ b/lldb/tools/debugserver/source/SysSignal.h
@@ -0,0 +1,23 @@
+//===-- SysSignal.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 6/18/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __SysSignal_h__
+#define __SysSignal_h__
+
+class SysSignal
+{
+public:
+ static const char *Name(int signal);
+};
+
+#endif
diff --git a/lldb/tools/debugserver/source/TTYState.cpp b/lldb/tools/debugserver/source/TTYState.cpp
new file mode 100644
index 00000000000..28bc956dc28
--- /dev/null
+++ b/lldb/tools/debugserver/source/TTYState.cpp
@@ -0,0 +1,122 @@
+//===-- TTYState.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 3/26/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TTYState.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/signal.h>
+
+TTYState::TTYState() :
+ m_fd(-1),
+ m_tflags(-1),
+ m_ttystateErr(-1),
+ m_processGroup(-1)
+{
+}
+
+TTYState::~TTYState()
+{
+}
+
+bool
+TTYState::GetTTYState (int fd, bool saveProcessGroup)
+{
+ if (fd >= 0 && ::isatty (fd))
+ {
+ m_fd = fd;
+ m_tflags = fcntl (fd, F_GETFL, 0);
+ m_ttystateErr = tcgetattr (fd, &m_ttystate);
+ if (saveProcessGroup)
+ m_processGroup = tcgetpgrp (0);
+ else
+ m_processGroup = -1;
+ }
+ else
+ {
+ m_fd = -1;
+ m_tflags = -1;
+ m_ttystateErr = -1;
+ m_processGroup = -1;
+ }
+ return m_ttystateErr == 0;
+}
+
+bool
+TTYState::SetTTYState () const
+{
+ int result = 0;
+ if (IsValid())
+ {
+ if (TFlagsValid())
+ result = fcntl (m_fd, F_SETFL, m_tflags);
+
+ if (TTYStateValid())
+ result = tcsetattr (m_fd, TCSANOW, &m_ttystate);
+
+ if (ProcessGroupValid())
+ {
+ // Save the original signal handler.
+ void (*saved_sigttou_callback) (int) = NULL;
+ saved_sigttou_callback = (void (*)(int)) signal (SIGTTOU, SIG_IGN);
+ // Set the process group
+ result = tcsetpgrp (m_fd, m_processGroup);
+ // Restore the original signal handler.
+ signal (SIGTTOU, saved_sigttou_callback);
+ }
+ return true;
+ }
+ return false;
+}
+
+
+
+TTYStateSwitcher::TTYStateSwitcher() :
+ m_currentState(~0)
+{
+}
+
+TTYStateSwitcher::~TTYStateSwitcher()
+{
+}
+
+bool
+TTYStateSwitcher::GetState(uint32_t idx, int fd, bool saveProcessGroup)
+{
+ if (ValidStateIndex(idx))
+ return m_ttystates[idx].GetTTYState(fd, saveProcessGroup);
+ return false;
+}
+
+bool
+TTYStateSwitcher::SetState(uint32_t idx) const
+{
+ if (!ValidStateIndex(idx))
+ return false;
+
+ // See if we already are in this state?
+ if (ValidStateIndex(m_currentState) && (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].SetTTYState())
+ {
+ m_currentState = idx;
+ return true;
+ }
+
+ // We failed to set the state. The tty state was invalid or not
+ // initialized.
+ return false;
+}
+
diff --git a/lldb/tools/debugserver/source/TTYState.h b/lldb/tools/debugserver/source/TTYState.h
new file mode 100644
index 00000000000..c01d5125543
--- /dev/null
+++ b/lldb/tools/debugserver/source/TTYState.h
@@ -0,0 +1,61 @@
+//===-- TTYState.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Created by Greg Clayton on 3/26/07.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __TTYState_h__
+#define __TTYState_h__
+
+#include <termios.h>
+#include <stdint.h>
+
+class TTYState
+{
+public:
+ TTYState();
+ ~TTYState();
+
+ bool GetTTYState (int fd, bool saveProcessGroup);
+ bool SetTTYState () const;
+
+ bool IsValid() const { return FileDescriptorValid() && TFlagsValid() && TTYStateValid(); }
+ bool FileDescriptorValid() const { return m_fd >= 0; }
+ bool TFlagsValid() const { return m_tflags != -1; }
+ bool TTYStateValid() const { return m_ttystateErr == 0; }
+ bool ProcessGroupValid() const { return m_processGroup != -1; }
+
+protected:
+ int m_fd; // File descriptor
+ int m_tflags;
+ int m_ttystateErr;
+ struct termios m_ttystate;
+ pid_t m_processGroup;
+
+};
+
+
+class TTYStateSwitcher
+{
+public:
+ TTYStateSwitcher();
+ ~TTYStateSwitcher();
+
+ bool GetState(uint32_t idx, int fd, bool saveProcessGroup);
+ bool SetState(uint32_t idx) const;
+ uint32_t NumStates() const { return sizeof(m_ttystates)/sizeof(TTYState); }
+ bool ValidStateIndex(uint32_t idx) const { return idx < NumStates(); }
+
+protected:
+ mutable uint32_t m_currentState;
+ TTYState m_ttystates[2];
+};
+
+#endif \ No newline at end of file
diff --git a/lldb/tools/debugserver/source/com.apple.debugserver.applist.plist b/lldb/tools/debugserver/source/com.apple.debugserver.applist.plist
new file mode 100644
index 00000000000..4e847c20a71
--- /dev/null
+++ b/lldb/tools/debugserver/source/com.apple.debugserver.applist.plist
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.apple.debugserver.applist</string>
+ <key>UserName</key>
+ <string>mobile</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/Developer/usr/bin/debugserver</string>
+ <string>--lockdown</string>
+ <string>--applist</string>
+ </array>
+</dict>
+</plist>
diff --git a/lldb/tools/debugserver/source/com.apple.debugserver.plist b/lldb/tools/debugserver/source/com.apple.debugserver.plist
new file mode 100644
index 00000000000..aa72606e098
--- /dev/null
+++ b/lldb/tools/debugserver/source/com.apple.debugserver.plist
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.apple.debugserver</string>
+ <key>UserName</key>
+ <string>mobile</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/Developer/usr/bin/debugserver</string>
+ <string>--lockdown</string>
+ </array>
+</dict>
+</plist>
diff --git a/lldb/tools/debugserver/source/debugserver-entitlements.plist b/lldb/tools/debugserver/source/debugserver-entitlements.plist
new file mode 100644
index 00000000000..ce8bd5bc4c0
--- /dev/null
+++ b/lldb/tools/debugserver/source/debugserver-entitlements.plist
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.springboard.debugapplications</key>
+ <true/>
+ <key>run-unsigned-code</key>
+ <true/>
+ <key>seatbelt-profiles</key>
+ <array>
+ <string>debugserver</string>
+ </array>
+</dict>
+</plist>
diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp
new file mode 100644
index 00000000000..f3041dbbf3a
--- /dev/null
+++ b/lldb/tools/debugserver/source/debugserver.cpp
@@ -0,0 +1,1219 @@
+//===-- debugserver.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <getopt.h>
+#include <netinet/in.h>
+#include <sys/select.h>
+#include <sys/sysctl.h>
+#include <string>
+#include <vector>
+#include <asl.h>
+
+#include "CFString.h"
+#include "DNB.h"
+#include "DNBLog.h"
+#include "DNBTimer.h"
+#include "PseudoTerminal.h"
+#include "RNBContext.h"
+#include "RNBServices.h"
+#include "RNBSocket.h"
+#include "RNBRemote.h"
+#include "SysSignal.h"
+
+// Global PID in case we get a signal and need to stop the process...
+nub_process_t g_pid = INVALID_NUB_PROCESS;
+
+//----------------------------------------------------------------------
+// Run loop modes which determine which run loop function will be called
+//----------------------------------------------------------------------
+typedef enum
+{
+ eRNBRunLoopModeInvalid = 0,
+ eRNBRunLoopModeGetStartModeFromRemoteProtocol,
+ eRNBRunLoopModeInferiorAttaching,
+ eRNBRunLoopModeInferiorLaunching,
+ eRNBRunLoopModeInferiorExecuting,
+ eRNBRunLoopModeExit
+} RNBRunLoopMode;
+
+
+//----------------------------------------------------------------------
+// Global Variables
+//----------------------------------------------------------------------
+RNBRemoteSP g_remoteSP;
+static int g_lockdown_opt = 0;
+static int g_applist_opt = 0;
+static nub_launch_flavor_t g_launch_flavor = eLaunchFlavorDefault;
+
+int g_isatty = 0;
+
+#define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
+#define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
+
+//----------------------------------------------------------------------
+// Run Loop function prototypes
+//----------------------------------------------------------------------
+RNBRunLoopMode RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remote);
+RNBRunLoopMode RNBRunLoopInferiorExecuting (RNBRemoteSP &remote);
+
+
+//----------------------------------------------------------------------
+// Get our program path and arguments from the remote connection.
+// We will need to start up the remote connection without a PID, get the
+// arguments, wait for the new process to finish launching and hit its
+// entry point, and then return the run loop mode that should come next.
+//----------------------------------------------------------------------
+RNBRunLoopMode
+RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP)
+{
+ std::string packet;
+
+ if (remoteSP.get() != NULL)
+ {
+ RNBRemote* remote = remoteSP.get();
+ RNBContext& ctx = remote->Context();
+ uint32_t event_mask = RNBContext::event_read_packet_available;
+
+ // Spin waiting to get the A packet.
+ while (1)
+ {
+ DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask);
+ nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
+ DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events);
+
+ if (set_events & RNBContext::event_read_packet_available)
+ {
+ rnb_err_t err = rnb_err;
+ RNBRemote::PacketEnum type;
+
+ err = remote->HandleReceivedPacket (&type);
+
+ // check if we tried to attach to a process
+ if (type == RNBRemote::vattach || type == RNBRemote::vattachwait)
+ {
+ if (err == rnb_success)
+ return eRNBRunLoopModeInferiorExecuting;
+ else
+ {
+ RNBLogSTDERR ("error: attach failed.");
+ return eRNBRunLoopModeExit;
+ }
+ }
+
+ if (err == rnb_success)
+ {
+ // If we got our arguments we are ready to launch using the arguments
+ // and any environment variables we received.
+ if (type == RNBRemote::set_argv)
+ {
+ return eRNBRunLoopModeInferiorLaunching;
+ }
+ }
+ else if (err == rnb_not_connected)
+ {
+ RNBLogSTDERR ("error: connection lost.");
+ return eRNBRunLoopModeExit;
+ }
+ else
+ {
+ // a catch all for any other gdb remote packets that failed
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__);
+ continue;
+ }
+
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
+ }
+ else
+ {
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__);
+ return eRNBRunLoopModeExit;
+ }
+ }
+ }
+ return eRNBRunLoopModeExit;
+}
+
+
+//----------------------------------------------------------------------
+// This run loop mode will wait for the process to launch and hit its
+// entry point. It will currently ignore all events except for the
+// process state changed event, where it watches for the process stopped
+// or crash process state.
+//----------------------------------------------------------------------
+RNBRunLoopMode
+RNBRunLoopLaunchInferior (RNBRemoteSP &remote, const char *stdio_path)
+{
+ RNBContext& ctx = remote->Context();
+
+ // The Process stuff takes a c array, the RNBContext has a vector...
+ // So make up a c array.
+
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, ctx.ArgumentAtIndex(0));
+
+ size_t inferior_argc = ctx.ArgumentCount();
+ // Initialize inferior_argv with inferior_argc + 1 NULLs
+ std::vector<const char *> inferior_argv(inferior_argc + 1, NULL);
+
+ size_t i;
+ for (i = 0; i < inferior_argc; i++)
+ inferior_argv[i] = ctx.ArgumentAtIndex(i);
+
+ // Pass the environment array the same way:
+
+ size_t inferior_envc = ctx.EnvironmentCount();
+ // Initialize inferior_argv with inferior_argc + 1 NULLs
+ std::vector<const char *> inferior_envp(inferior_envc + 1, NULL);
+
+ for (i = 0; i < inferior_envc; i++)
+ inferior_envp[i] = ctx.EnvironmentAtIndex(i);
+
+ // Our launch type hasn't been set to anything concrete, so we need to
+ // figure our how we are going to launch automatically.
+
+ nub_launch_flavor_t launch_flavor = g_launch_flavor;
+ if (launch_flavor == eLaunchFlavorDefault)
+ {
+ // Our default launch method is posix spawn
+ launch_flavor = eLaunchFlavorPosixSpawn;
+
+#if defined (__arm__)
+ // Check if we have an app bundle, if so launch using SpringBoard.
+ if (strstr(inferior_argv[0], ".app"))
+ {
+ launch_flavor = eLaunchFlavorSpringBoard;
+ }
+#endif
+ }
+
+ ctx.SetLaunchFlavor(launch_flavor);
+ char resolved_path[PATH_MAX];
+
+ // If we fail to resolve the path to our executable, then just use what we
+ // were given and hope for the best
+ if ( !DNBResolveExecutablePath (inferior_argv[0], resolved_path, sizeof(resolved_path)) )
+ ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path));
+
+ char launch_err_str[PATH_MAX];
+ launch_err_str[0] = '\0';
+ nub_process_t pid = DNBProcessLaunch (resolved_path,
+ &inferior_argv[0],
+ &inferior_envp[0],
+ stdio_path,
+ launch_flavor,
+ launch_err_str,
+ sizeof(launch_err_str));
+
+ g_pid = pid;
+
+ if (pid == INVALID_NUB_PROCESS && strlen(launch_err_str) > 0)
+ {
+ DNBLogThreaded ("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__);
+ ctx.LaunchStatus().SetError(-1, DNBError::Generic);
+ ctx.LaunchStatus().SetErrorString(launch_err_str);
+ }
+ else
+ ctx.LaunchStatus().Clear();
+
+ if (remote->Comm().IsConnected())
+ {
+ // It we are connected already, the next thing gdb will do is ask
+ // whether the launch succeeded, and if not, whether there is an
+ // error code. So we need to fetch one packet from gdb before we wait
+ // on the stop from the target.
+
+ uint32_t event_mask = RNBContext::event_read_packet_available;
+ nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
+
+ if (set_events & RNBContext::event_read_packet_available)
+ {
+ rnb_err_t err = rnb_err;
+ RNBRemote::PacketEnum type;
+
+ err = remote->HandleReceivedPacket (&type);
+
+ if (err != rnb_success)
+ {
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.", __FUNCTION__);
+ return eRNBRunLoopModeExit;
+ }
+ if (type != RNBRemote::query_launch_success)
+ {
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__);
+ }
+ }
+ }
+
+ while (pid != INVALID_NUB_PROCESS)
+ {
+ // Wait for process to start up and hit entry point
+ DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", __FUNCTION__, pid);
+ nub_event_t set_events = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, NULL);
+ DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", __FUNCTION__, pid, set_events);
+
+ if (set_events == 0)
+ {
+ pid = INVALID_NUB_PROCESS;
+ g_pid = pid;
+ }
+ else
+ {
+ if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
+ {
+ nub_state_t pid_state = DNBProcessGetState (pid);
+ DNBLogThreadedIf (LOG_RNB_EVENTS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
+
+ switch (pid_state)
+ {
+ default:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateSuspended:
+ break; // Ignore
+
+ case eStateRunning:
+ case eStateStepping:
+ // Still waiting to stop at entry point...
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ ctx.SetProcessID(pid);
+ return eRNBRunLoopModeInferiorExecuting;
+
+ case eStateDetached:
+ case eStateExited:
+ pid = INVALID_NUB_PROCESS;
+ g_pid = pid;
+ return eRNBRunLoopModeExit;
+ }
+ }
+
+ DNBProcessResetEvents(pid, set_events);
+ }
+ }
+
+ return eRNBRunLoopModeExit;
+}
+
+
+//----------------------------------------------------------------------
+// This run loop mode will wait for the process to launch and hit its
+// entry point. It will currently ignore all events except for the
+// process state changed event, where it watches for the process stopped
+// or crash process state.
+//----------------------------------------------------------------------
+RNBRunLoopMode
+RNBRunLoopLaunchAttaching (RNBRemoteSP &remote, nub_process_t attach_pid, nub_process_t& pid)
+{
+ RNBContext& ctx = remote->Context();
+
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid);
+ char err_str[1024];
+ pid = DNBProcessAttach (attach_pid, NULL, err_str, sizeof(err_str));
+ g_pid = pid;
+
+ if (pid == INVALID_NUB_PROCESS)
+ {
+ ctx.LaunchStatus().SetError(-1, DNBError::Generic);
+ if (err_str[0])
+ ctx.LaunchStatus().SetErrorString(err_str);
+ return eRNBRunLoopModeExit;
+ }
+ else
+ {
+
+ ctx.SetProcessID(pid);
+ return eRNBRunLoopModeInferiorExecuting;
+ }
+}
+
+//----------------------------------------------------------------------
+// Watch for signals:
+// SIGINT: so we can halt our inferior. (disabled for now)
+// SIGPIPE: in case our child process dies
+//----------------------------------------------------------------------
+int g_sigint_received = 0;
+int g_sigpipe_received = 0;
+void
+signal_handler(int signo)
+{
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo));
+
+ switch (signo)
+ {
+ case SIGINT:
+ g_sigint_received++;
+ if (g_pid != INVALID_NUB_PROCESS)
+ {
+ // Only send a SIGINT once...
+ if (g_sigint_received == 1)
+ {
+ switch (DNBProcessGetState (g_pid))
+ {
+ case eStateRunning:
+ case eStateStepping:
+ DNBProcessSignal (g_pid, SIGSTOP);
+ return;
+ }
+ }
+ }
+ exit (SIGINT);
+ break;
+
+ case SIGPIPE:
+ g_sigpipe_received = 1;
+ break;
+ }
+}
+
+// Return the new run loop mode based off of the current process state
+RNBRunLoopMode
+HandleProcessStateChange (RNBRemoteSP &remote, bool initialize)
+{
+ RNBContext& ctx = remote->Context();
+ nub_process_t pid = ctx.ProcessID();
+
+ if (pid == INVALID_NUB_PROCESS)
+ {
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__);
+ return eRNBRunLoopModeExit;
+ }
+ nub_state_t pid_state = DNBProcessGetState (pid);
+
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state));
+
+ switch (pid_state)
+ {
+ case eStateInvalid:
+ case eStateUnloaded:
+ // Something bad happened
+ return eRNBRunLoopModeExit;
+ break;
+
+ case eStateAttaching:
+ case eStateLaunching:
+ return eRNBRunLoopModeInferiorExecuting;
+
+ case eStateSuspended:
+ case eStateCrashed:
+ case eStateStopped:
+ // If we stop due to a signal, so clear the fact that we got a SIGINT
+ // so we can stop ourselves again (but only while our inferior
+ // process is running..)
+ g_sigint_received = 0;
+ if (initialize == false)
+ {
+ // Compare the last stop count to our current notion of a stop count
+ // to make sure we don't notify more than once for a given stop.
+ nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount();
+ bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid));
+ if (pid_stop_count_changed)
+ {
+ remote->FlushSTDIO();
+
+ if (ctx.GetProcessStopCount() == 1)
+ {
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
+ }
+ else
+ {
+
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? YES!!!", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
+ remote->NotifyThatProcessStopped ();
+ }
+ }
+ else
+ {
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? skipping...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
+ }
+ }
+ return eRNBRunLoopModeInferiorExecuting;
+
+ case eStateStepping:
+ case eStateRunning:
+ return eRNBRunLoopModeInferiorExecuting;
+
+ case eStateExited:
+ remote->HandlePacket_last_signal(NULL);
+ return eRNBRunLoopModeExit;
+
+ }
+
+ // Catch all...
+ return eRNBRunLoopModeExit;
+}
+// This function handles the case where our inferior program is stopped and
+// we are waiting for gdb remote protocol packets. When a packet occurs that
+// makes the inferior run, we need to leave this function with a new state
+// as the return code.
+RNBRunLoopMode
+RNBRunLoopInferiorExecuting (RNBRemoteSP &remote)
+{
+ DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
+ RNBContext& ctx = remote->Context();
+
+ // Init our mode and set 'is_running' based on the current process state
+ RNBRunLoopMode mode = HandleProcessStateChange (remote, true);
+
+ while (ctx.ProcessID() != INVALID_NUB_PROCESS)
+ {
+
+ std::string set_events_str;
+ uint32_t event_mask = ctx.NormalEventBits();
+
+ if (!ctx.ProcessStateRunning())
+ {
+ // Clear the stdio bits if we are not running so we don't send any async packets
+ event_mask &= ~RNBContext::event_proc_stdio_available;
+ }
+
+ // We want to make sure we consume all process state changes and have
+ // whomever is notifying us to wait for us to reset the event bit before
+ // continuing.
+ //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed);
+
+ DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
+ nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
+ DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) => 0x%08x (%s)",__FUNCTION__, event_mask, set_events, ctx.EventsAsString(set_events, set_events_str));
+
+ if (set_events)
+ {
+ if ((set_events & RNBContext::event_proc_thread_exiting) ||
+ (set_events & RNBContext::event_proc_stdio_available))
+ {
+ remote->FlushSTDIO();
+ }
+
+ if (set_events & RNBContext::event_read_packet_available)
+ {
+ // handleReceivedPacket will take care of resetting the
+ // event_read_packet_available events when there are no more...
+ set_events ^= RNBContext::event_read_packet_available;
+
+ if (ctx.ProcessStateRunning())
+ {
+ if (remote->HandleAsyncPacket() == rnb_not_connected)
+ {
+ // TODO: connect again? Exit?
+ }
+ }
+ else
+ {
+ if (remote->HandleReceivedPacket() == rnb_not_connected)
+ {
+ // TODO: connect again? Exit?
+ }
+ }
+ }
+
+ if (set_events & RNBContext::event_proc_state_changed)
+ {
+ mode = HandleProcessStateChange (remote, false);
+ ctx.Events().ResetEvents(RNBContext::event_proc_state_changed);
+ set_events ^= RNBContext::event_proc_state_changed;
+ }
+
+ if (set_events & RNBContext::event_proc_thread_exiting)
+ {
+ mode = eRNBRunLoopModeExit;
+ }
+
+ if (set_events & RNBContext::event_read_thread_exiting)
+ {
+ // Out remote packet receiving thread exited, exit for now.
+ if (ctx.HasValidProcessID())
+ {
+ // TODO: We should add code that will leave the current process
+ // in its current state and listen for another connection...
+ if (ctx.ProcessStateRunning())
+ {
+ DNBProcessKill (ctx.ProcessID());
+ }
+ }
+ mode = eRNBRunLoopModeExit;
+ }
+ }
+
+ // Reset all event bits that weren't reset for now...
+ if (set_events != 0)
+ ctx.Events().ResetEvents(set_events);
+
+ if (mode != eRNBRunLoopModeInferiorExecuting)
+ break;
+ }
+
+ return mode;
+}
+
+
+//----------------------------------------------------------------------
+// Convenience function to set up the remote listening port
+// Returns 1 for success 0 for failure.
+//----------------------------------------------------------------------
+
+static int
+StartListening (RNBRemoteSP remoteSP, int listen_port)
+{
+ if (!remoteSP->Comm().IsConnected())
+ {
+ RNBLogSTDOUT ("Listening to port %i...\n", listen_port);
+ if (remoteSP->Comm().Listen(listen_port) != rnb_success)
+ {
+ RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
+ return 0;
+ }
+ else
+ {
+ remoteSP->StartReadRemoteDataThread();
+ }
+ }
+ return 1;
+}
+
+//----------------------------------------------------------------------
+// ASL Logging callback that can be registered with DNBLogSetLogCallback
+//----------------------------------------------------------------------
+void
+ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
+{
+ if (format == NULL)
+ return;
+ static aslmsg g_aslmsg = NULL;
+ if (g_aslmsg == NULL)
+ {
+ g_aslmsg = ::asl_new (ASL_TYPE_MSG);
+ char asl_key_sender[PATH_MAX];
+ snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.%s-%g", DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_NUM);
+ ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
+ }
+
+ int asl_level;
+ if (flags & DNBLOG_FLAG_FATAL) asl_level = ASL_LEVEL_CRIT;
+ else if (flags & DNBLOG_FLAG_ERROR) asl_level = ASL_LEVEL_ERR;
+ else if (flags & DNBLOG_FLAG_WARNING) asl_level = ASL_LEVEL_WARNING;
+ else if (flags & DNBLOG_FLAG_VERBOSE) asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_INFO;
+ else asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_DEBUG;
+
+ ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
+}
+
+//----------------------------------------------------------------------
+// FILE based Logging callback that can be registered with
+// DNBLogSetLogCallback
+//----------------------------------------------------------------------
+void
+FileLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
+{
+ if (baton == NULL || format == NULL)
+ return;
+
+ ::vfprintf ((FILE *)baton, format, args);
+ ::fprintf ((FILE *)baton, "\n");
+}
+
+
+void
+show_usage_and_exit (int exit_code)
+{
+ RNBLogSTDERR ("Usage:\n %s host:port [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
+ RNBLogSTDERR (" %s /path/file [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
+ RNBLogSTDERR (" %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
+ RNBLogSTDERR (" %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
+ RNBLogSTDERR (" %s host:port --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
+ RNBLogSTDERR (" %s /path/file --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
+ exit (exit_code);
+}
+
+
+//----------------------------------------------------------------------
+// option descriptors for getopt_long()
+//----------------------------------------------------------------------
+static struct option g_long_options[] =
+{
+ { "attach", required_argument, NULL, 'a' },
+ { "debug", no_argument, NULL, 'g' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "lockdown", no_argument, &g_lockdown_opt, 1 }, // short option "-k"
+ { "applist", no_argument, &g_applist_opt, 1 }, // short option "-t"
+ { "log-file", required_argument, NULL, 'l' },
+ { "log-flags", required_argument, NULL, 'f' },
+ { "launch", required_argument, NULL, 'x' }, // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only)
+ { "waitfor", required_argument, NULL, 'w' }, // Wait for a process whose name starts with ARG
+ { "waitfor-interval", required_argument, NULL, 'i' }, // Time in usecs to wait between sampling the pid list when waiting for a process by name
+ { "waitfor-duration", required_argument, NULL, 'd' }, // The time in seconds to wait for a process to show up by name
+ { "native-regs", no_argument, NULL, 'r' }, // Specify to use the native registers instead of the gdb defaults for the architecture.
+ { "stdio-path", required_argument, NULL, 's' }, // Set the STDIO path to be used when launching applications
+ { "setsid", no_argument, NULL, 'S' }, // call setsid() to make debugserver run in its own sessions
+ { NULL, 0, NULL, 0 }
+};
+
+
+//----------------------------------------------------------------------
+// main
+//----------------------------------------------------------------------
+int
+main (int argc, char *argv[])
+{
+ g_isatty = ::isatty (STDIN_FILENO);
+
+ // ::printf ("uid=%u euid=%u gid=%u egid=%u\n",
+ // getuid(),
+ // geteuid(),
+ // getgid(),
+ // getegid());
+
+
+ // signal (SIGINT, signal_handler);
+ signal (SIGPIPE, signal_handler);
+
+ int i;
+ int attach_pid = INVALID_NUB_PROCESS;
+
+ FILE* log_file = NULL;
+ uint32_t log_flags = 0;
+ // Parse our options
+ int ch;
+ int long_option_index = 0;
+ int use_native_registers = 0;
+ int debug = 0;
+ std::string compile_options;
+ std::string waitfor_pid_name; // Wait for a process that starts with this name
+ std::string attach_pid_name;
+ std::string stdio_path;
+ useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
+ useconds_t waitfor_duration = 0; // Time in seconds to wait for a process by name, 0 means wait forever.
+
+#if !defined (DNBLOG_ENABLED)
+ compile_options += "(no-logging) ";
+#endif
+
+ RNBRunLoopMode start_mode = eRNBRunLoopModeExit;
+
+ while ((ch = getopt_long(argc, argv, "a:d:gi:vktl:f:w:x:r", g_long_options, &long_option_index)) != -1)
+ {
+ DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n",
+ ch, (uint8_t)ch,
+ g_long_options[long_option_index].name,
+ g_long_options[long_option_index].has_arg ? '=' : ' ',
+ optarg ? optarg : "");
+ switch (ch)
+ {
+ case 0: // Any optional that auto set themselves will return 0
+ break;
+
+ case 'a':
+ if (optarg && optarg[0])
+ {
+ if (isdigit(optarg[0]))
+ {
+ char *end = NULL;
+ attach_pid = strtoul(optarg, &end, 0);
+ if (end == NULL || *end != '\0')
+ {
+ RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg);
+ exit (4);
+ }
+ }
+ else
+ {
+ attach_pid_name = optarg;
+ }
+ start_mode = eRNBRunLoopModeInferiorAttaching;
+ }
+ break;
+
+ // --waitfor=NAME
+ case 'w':
+ if (optarg && optarg[0])
+ {
+ waitfor_pid_name = optarg;
+ start_mode = eRNBRunLoopModeInferiorAttaching;
+ }
+ break;
+
+ // --waitfor-interval=USEC
+ case 'i':
+ if (optarg && optarg[0])
+ {
+ char *end = NULL;
+ waitfor_interval = strtoul(optarg, &end, 0);
+ if (end == NULL || *end != '\0')
+ {
+ RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg);
+ exit (6);
+ }
+ }
+ break;
+
+ // --waitfor-duration=SEC
+ case 'd':
+ if (optarg && optarg[0])
+ {
+ char *end = NULL;
+ waitfor_duration = strtoul(optarg, &end, 0);
+ if (end == NULL || *end != '\0')
+ {
+ RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg);
+ exit (7);
+ }
+ }
+ break;
+
+ case 'x':
+ if (optarg && optarg[0])
+ {
+ if (strcasecmp(optarg, "auto") == 0)
+ g_launch_flavor = eLaunchFlavorDefault;
+ else if (strcasestr(optarg, "posix") == optarg)
+ g_launch_flavor = eLaunchFlavorPosixSpawn;
+ else if (strcasestr(optarg, "fork") == optarg)
+ g_launch_flavor = eLaunchFlavorForkExec;
+#if defined (__arm__)
+ else if (strcasestr(optarg, "spring") == optarg)
+ g_launch_flavor = eLaunchFlavorSpringBoard;
+#endif
+ else
+ {
+ RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg);
+ RNBLogSTDERR ("Valid values TYPE are:\n");
+ RNBLogSTDERR (" auto Auto-detect the best launch method to use.\n");
+ RNBLogSTDERR (" posix Launch the executable using posix_spawn.\n");
+ RNBLogSTDERR (" fork Launch the executable using fork and exec.\n");
+#if defined (__arm__)
+ RNBLogSTDERR (" spring Launch the executable through Springboard.\n");
+#endif
+ exit (5);
+ }
+ }
+ break;
+
+ case 'l': // Set Log File
+ if (optarg && optarg[0])
+ {
+ if (strcasecmp(optarg, "stdout") == 0)
+ log_file = stdout;
+ else if (strcasecmp(optarg, "stderr") == 0)
+ log_file = stderr;
+ else
+ log_file = fopen(optarg, "w+");
+
+ if (log_file == NULL)
+ {
+ const char *errno_str = strerror(errno);
+ RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
+ }
+ }
+ break;
+
+ case 'f': // Log Flags
+ if (optarg && optarg[0])
+ log_flags = strtoul(optarg, NULL, 0);
+ break;
+
+ case 'g':
+ debug = 1;
+ DNBLogSetDebug(1);
+ break;
+
+ case 't':
+ g_applist_opt = 1;
+ break;
+
+ case 'k':
+ g_lockdown_opt = 1;
+ break;
+
+ case 'r':
+ use_native_registers = 1;
+ break;
+
+ case 'v':
+ DNBLogSetVerbose(1);
+ break;
+
+ case 's':
+ stdio_path = optarg;
+ break;
+
+ case 'S':
+ // Put debugserver into a new session. Terminals group processes
+ // into sessions and when a special terminal key sequences
+ // (like control+c) are typed they can cause signals to go out to
+ // all processes in a session. Using this --setsid (-S) option
+ // will cause debugserver to run in its own sessions and be free
+ // from such issues.
+ //
+ // This is useful when debugserver is spawned from a command
+ // line application that uses debugserver to do the debugging,
+ // yet that application doesn't want debugserver receiving the
+ // signals sent to the session (i.e. dying when anyone hits ^C).
+ setsid();
+ break;
+ }
+ }
+
+ // Skip any options we consumed with getopt_long
+ argc -= optind;
+ argv += optind;
+
+ g_remoteSP.reset (new RNBRemote (use_native_registers));
+
+ RNBRemote *remote = g_remoteSP.get();
+ if (remote == NULL)
+ {
+ RNBLogSTDERR ("error: failed to create a remote connection class\n");
+ return -1;
+ }
+
+ RNBContext& ctx = remote->Context();
+
+
+ // It is ok for us to set NULL as the logfile (this will disable any logging)
+
+ if (log_file != NULL)
+ {
+ DNBLogSetLogCallback(FileLogCallback, log_file);
+ // If our log file was set, yet we have no log flags, log everything!
+ if (log_flags == 0)
+ log_flags = LOG_ALL | LOG_RNB_ALL;
+
+ DNBLogSetLogMask (log_flags);
+ }
+ else
+ {
+ // Enable DNB logging
+ DNBLogSetLogCallback(ASLLogCallback, NULL);
+ DNBLogSetLogMask (log_flags);
+
+ }
+
+ if (DNBLogEnabled())
+ {
+ for (i=0; i<argc; i++)
+ DNBLogDebug("argv[%i] = %s", i, argv[i]);
+ }
+
+ // Now that we have read in the options and enabled logging, initialize
+ // the rest of RNBRemote
+ RNBRemote::InitializeRegisters (use_native_registers);
+
+
+ // as long as we're dropping remotenub in as a replacement for gdbserver,
+ // explicitly note that this is not gdbserver.
+
+ RNBLogSTDOUT ("%s-%g %sfor %s.\n",
+ DEBUGSERVER_PROGRAM_NAME,
+ DEBUGSERVER_VERSION_NUM,
+ compile_options.c_str(),
+ RNB_ARCH);
+
+ int listen_port = INT32_MAX;
+ char str[PATH_MAX];
+
+ if (g_lockdown_opt == 0 && g_applist_opt == 0)
+ {
+ // Make sure we at least have port
+ if (argc < 1)
+ {
+ show_usage_and_exit (1);
+ }
+ // accept 'localhost:' prefix on port number
+
+ int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &listen_port);
+ if (items_scanned == 2)
+ {
+ DNBLogDebug("host = '%s' port = %i", str, listen_port);
+ }
+ else if (argv[0][0] == '/')
+ {
+ listen_port = INT32_MAX;
+ strncpy(str, argv[0], sizeof(str));
+ }
+ else
+ {
+ show_usage_and_exit (2);
+ }
+
+ // We just used the 'host:port' or the '/path/file' arg...
+ argc--;
+ argv++;
+
+ }
+
+ // If we know we're waiting to attach, we don't need any of this other info.
+ if (start_mode != eRNBRunLoopModeInferiorAttaching)
+ {
+ if (argc == 0 || g_lockdown_opt)
+ {
+ if (g_lockdown_opt != 0)
+ {
+ // Work around for SIGPIPE crashes due to posix_spawn issue.
+ // We have to close STDOUT and STDERR, else the first time we
+ // try and do any, we get SIGPIPE and die as posix_spawn is
+ // doing bad things with our file descriptors at the moment.
+ int null = open("/dev/null", O_RDWR);
+ dup2(null, STDOUT_FILENO);
+ dup2(null, STDERR_FILENO);
+ }
+ else if (g_applist_opt != 0)
+ {
+ // List all applications we are able to see
+ std::string applist_plist;
+ int err = ListApplications(applist_plist, false, false);
+ if (err == 0)
+ {
+ fputs (applist_plist.c_str(), stdout);
+ }
+ else
+ {
+ RNBLogSTDERR ("error: ListApplications returned error %i\n", err);
+ }
+ // Exit with appropriate error if we were asked to list the applications
+ // with no other args were given (and we weren't trying to do this over
+ // lockdown)
+ return err;
+ }
+
+ DNBLogDebug("Get args from remote protocol...");
+ start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
+ }
+ else
+ {
+ start_mode = eRNBRunLoopModeInferiorLaunching;
+ // Fill in the argv array in the context from the rest of our args.
+ // Skip the name of this executable and the port number
+ for (int i = 0; i < argc; i++)
+ {
+ DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]);
+ ctx.PushArgument (argv[i]);
+ }
+ }
+ }
+
+ if (start_mode == eRNBRunLoopModeExit)
+ return -1;
+
+ RNBRunLoopMode mode = start_mode;
+ char err_str[1024] = {'\0'};
+
+ while (mode != eRNBRunLoopModeExit)
+ {
+ switch (mode)
+ {
+ case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
+#if defined (__arm__)
+ if (g_lockdown_opt)
+ {
+ if (!g_remoteSP->Comm().IsConnected())
+ {
+ if (g_remoteSP->Comm().ConnectToService () != rnb_success)
+ {
+ RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
+ mode = eRNBRunLoopModeExit;
+ }
+ else if (g_applist_opt != 0)
+ {
+ // List all applications we are able to see
+ std::string applist_plist;
+ if (ListApplications(applist_plist, false, false) == 0)
+ {
+ DNBLogDebug("Task list: %s", applist_plist.c_str());
+
+ g_remoteSP->Comm().Write(applist_plist.c_str(), applist_plist.size());
+ // Issue a read that will never yield any data until the other side
+ // closes the socket so this process doesn't just exit and cause the
+ // socket to close prematurely on the other end and cause data loss.
+ std::string buf;
+ g_remoteSP->Comm().Read(buf);
+ }
+ g_remoteSP->Comm().Disconnect(false);
+ mode = eRNBRunLoopModeExit;
+ break;
+ }
+ else
+ {
+ // Start watching for remote packets
+ g_remoteSP->StartReadRemoteDataThread();
+ }
+ }
+ }
+ else
+#endif
+ if (listen_port != INT32_MAX)
+ {
+ if (!StartListening (g_remoteSP, listen_port))
+ mode = eRNBRunLoopModeExit;
+ }
+ else if (str[0] == '/')
+ {
+ if (g_remoteSP->Comm().OpenFile (str))
+ mode = eRNBRunLoopModeExit;
+ }
+ if (mode != eRNBRunLoopModeExit)
+ {
+ RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
+
+ mode = RNBRunLoopGetStartModeFromRemote (g_remoteSP);
+ }
+ break;
+
+ case eRNBRunLoopModeInferiorAttaching:
+ if (!waitfor_pid_name.empty())
+ {
+ // Set our end wait time if we are using a waitfor-duration
+ // option that may have been specified
+ struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
+ if (waitfor_duration != 0)
+ {
+ DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
+ timeout_ptr = &attach_timeout_abstime;
+ }
+ nub_launch_flavor_t launch_flavor = g_launch_flavor;
+ if (launch_flavor == eLaunchFlavorDefault)
+ {
+ // Our default launch method is posix spawn
+ launch_flavor = eLaunchFlavorPosixSpawn;
+
+#if defined (__arm__)
+ // Check if we have an app bundle, if so launch using SpringBoard.
+ if (waitfor_pid_name.find (".app") != std::string::npos)
+ {
+ launch_flavor = eLaunchFlavorSpringBoard;
+ }
+#endif
+ }
+
+ ctx.SetLaunchFlavor(launch_flavor);
+
+ nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, timeout_ptr, waitfor_interval, err_str, sizeof(err_str));
+ g_pid = pid;
+
+ if (pid == INVALID_NUB_PROCESS)
+ {
+ ctx.LaunchStatus().SetError(-1, DNBError::Generic);
+ if (err_str[0])
+ ctx.LaunchStatus().SetErrorString(err_str);
+ RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), err_str);
+ mode = eRNBRunLoopModeExit;
+ }
+ else
+ {
+ ctx.SetProcessID(pid);
+ mode = eRNBRunLoopModeInferiorExecuting;
+ }
+ }
+ else if (attach_pid != INVALID_NUB_PROCESS)
+ {
+
+ RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid);
+ nub_process_t attached_pid;
+ mode = RNBRunLoopLaunchAttaching (g_remoteSP, attach_pid, attached_pid);
+ if (mode != eRNBRunLoopModeInferiorExecuting)
+ {
+ const char *error_str = remote->Context().LaunchStatus().AsString();
+ RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error.");
+ mode = eRNBRunLoopModeExit;
+ }
+ }
+ else if (!attach_pid_name.empty ())
+ {
+ struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
+ if (waitfor_duration != 0)
+ {
+ DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
+ timeout_ptr = &attach_timeout_abstime;
+ }
+
+ nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str));
+ g_pid = pid;
+ if (pid == INVALID_NUB_PROCESS)
+ {
+ ctx.LaunchStatus().SetError(-1, DNBError::Generic);
+ if (err_str[0])
+ ctx.LaunchStatus().SetErrorString(err_str);
+ RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), err_str);
+ mode = eRNBRunLoopModeExit;
+ }
+ else
+ {
+ ctx.SetProcessID(pid);
+ mode = eRNBRunLoopModeInferiorExecuting;
+ }
+
+ }
+ else
+ {
+ RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.");
+ mode = eRNBRunLoopModeExit;
+ }
+
+ if (mode != eRNBRunLoopModeExit)
+ {
+ if (listen_port != INT32_MAX)
+ {
+ if (!StartListening (g_remoteSP, listen_port))
+ mode = eRNBRunLoopModeExit;
+ }
+ else if (str[0] == '/')
+ {
+ if (g_remoteSP->Comm().OpenFile (str))
+ mode = eRNBRunLoopModeExit;
+ }
+ if (mode != eRNBRunLoopModeExit)
+ RNBLogSTDOUT ("Got a connection, waiting for debugger instructions for process %d.\n", attach_pid);
+ }
+ break;
+
+ case eRNBRunLoopModeInferiorLaunching:
+ mode = RNBRunLoopLaunchInferior (g_remoteSP, stdio_path.empty() ? NULL : stdio_path.c_str());
+
+ if (mode == eRNBRunLoopModeInferiorExecuting)
+ {
+ if (listen_port != INT32_MAX)
+ {
+ if (!StartListening (g_remoteSP, listen_port))
+ mode = eRNBRunLoopModeExit;
+ }
+ else if (str[0] == '/')
+ {
+ if (g_remoteSP->Comm().OpenFile (str))
+ mode = eRNBRunLoopModeExit;
+ }
+
+ if (mode != eRNBRunLoopModeExit)
+ RNBLogSTDOUT ("Got a connection, waiting for debugger instructions.\n");
+ }
+ else
+ {
+ const char *error_str = remote->Context().LaunchStatus().AsString();
+ RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv[0], error_str ? error_str : "unknown error.");
+ }
+ break;
+
+ case eRNBRunLoopModeInferiorExecuting:
+ mode = RNBRunLoopInferiorExecuting(g_remoteSP);
+ break;
+
+ default:
+ mode = eRNBRunLoopModeExit;
+ case eRNBRunLoopModeExit:
+ break;
+ }
+ }
+
+ g_remoteSP->StopReadRemoteDataThread ();
+ g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS);
+
+ return 0;
+}
diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
new file mode 100644
index 00000000000..8cca697dd27
--- /dev/null
+++ b/lldb/tools/driver/Driver.cpp
@@ -0,0 +1,1265 @@
+//===-- 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>
+
+#include "IOChannel.h"
+#include <LLDB/SBCommandInterpreter.h>
+#include <LLDB/SBCommandReturnObject.h>
+#include <LLDB/SBCommunication.h>
+#include <LLDB/SBDebugger.h>
+#include <LLDB/SBEvent.h>
+#include <LLDB/SBHostOS.h>
+#include <LLDB/SBListener.h>
+#include <LLDB/SBSourceManager.h>
+#include <LLDB/SBTarget.h>
+#include <LLDB/SBThread.h>
+#include <LLDB/SBProcess.h>
+
+using namespace lldb;
+
+static void reset_stdin_termios ();
+static struct termios g_old_stdin_termios;
+
+// 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 ()
+{
+ ::tcsetattr (STDIN_FILENO, TCSANOW, &g_old_stdin_termios);
+}
+
+static lldb::OptionDefinition g_options[] =
+{
+ { 0, true, "help", 'h', no_argument, NULL, NULL, NULL,
+ "Prints out the usage information for the LLDB debugger." },
+
+ { 1, true, "version", 'v', no_argument, NULL, NULL, NULL,
+ "Prints out the current version number of the LLDB debugger." },
+
+ { 2, false, "file", 'f', required_argument, NULL, NULL, "<filename>",
+ "Tells the debugger to use the file <filename> as the program to be debugged." },
+
+ { 2, false, "arch", 'a', required_argument, NULL, NULL, "<architecture>",
+ "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." },
+
+ { 2, false, "script-language",'l', required_argument, NULL, NULL, "<scripting-language>",
+ "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." },
+
+ { 2, false, "debug", 'd', no_argument, NULL, NULL, NULL,
+ "Tells the debugger to print out extra information for debugging itself." },
+
+ { 2, false, "source", 's', required_argument, NULL, NULL, "<file>",
+ "Tells the debugger to read in and execute the file <file>, which should contain lldb commands." },
+
+ { 3, false, "crash-log", 'c', required_argument, NULL, NULL, "<file>",
+ "Load executable images from a crash log for symbolication." },
+
+ { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
+};
+
+
+Driver::Driver () :
+ SBBroadcaster ("Driver"),
+ m_editline_pty (),
+ m_editline_slave_fh (NULL),
+ m_editline_reader (),
+ m_io_channel_ap (),
+ m_option_data (),
+ m_waiting_for_command (false)
+{
+}
+
+Driver::~Driver ()
+{
+}
+
+void
+Driver::CloseIOChannelFile ()
+{
+ // Write and 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; SPACES, which is
+// a string that is output_max_columns long, containing 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
+OutputFormattedUsageText (FILE *out, int indent, char *spaces, const char *text, int output_max_columns)
+{
+ int len = strlen (text);
+ std::string text_string (text);
+ std::string spaces_string (spaces);
+
+ // 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", spaces_string.substr (0, indent).c_str(), 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", spaces_string.substr(0, indent).c_str(), substring.c_str());
+ start = end + 1;
+ }
+ }
+}
+
+void
+ShowUsage (FILE *out, lldb::OptionDefinition *option_table, Driver::OptionData data)
+{
+ uint32_t screen_width = 80;
+ uint32_t indent_level = 0;
+ const char *name = "lldb";
+ char spaces[screen_width+1];
+ uint32_t i;
+
+ for (i = 0; i < screen_width; ++i)
+ spaces[i] = ' ';
+ spaces[i] = '\n';
+
+ std::string spaces_string (spaces);
+
+ 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 usage_level = 0;
+ uint32_t num_options;
+
+ for (num_options = 0; option_table[num_options].long_option != NULL; ++num_options);
+
+ for (i = 0; i < num_options; ++i)
+ {
+ if (i == 0 || option_table[i].usage_level > usage_level)
+ {
+ // Start a new level.
+ usage_level = option_table[i].usage_level;
+ if (usage_level > 0)
+ fprintf (out, "\n\n");
+ fprintf (out, "%s%s", spaces_string.substr(0, indent_level).c_str(), name);
+ }
+
+ if (option_table[i].required)
+ {
+ if (option_table[i].option_has_arg == required_argument)
+ fprintf (out, " -%c %s", option_table[i].short_option, option_table[i].argument_name);
+ else if (option_table[i].option_has_arg == optional_argument)
+ fprintf (out, " -%c [%s]", option_table[i].short_option, option_table[i].argument_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, option_table[i].argument_name);
+ else if (option_table[i].option_has_arg == optional_argument)
+ fprintf (out, " [-%c [%s]]", option_table[i].short_option, option_table[i].argument_name);
+ else
+ fprintf (out, " [-%c]", option_table[i].short_option);
+ }
+ }
+
+ 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 (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())
+ {
+ options_seen.insert (option_table[i].short_option);
+ fprintf (out, "%s-%c ", spaces_string.substr(0, indent_level).c_str(), option_table[i].short_option);
+ if (option_table[i].argument_name != NULL)
+ fprintf (out, "%s", option_table[i].argument_name);
+ fprintf (out, "\n");
+ fprintf (out, "%s--%s ", spaces_string.substr(0, indent_level).c_str(), option_table[i].long_option);
+ if (option_table[i].argument_name != NULL)
+ fprintf (out, "%s", option_table[i].argument_name);
+ fprintf (out, "\n");
+ indent_level += 5;
+ OutputFormattedUsageText (out, indent_level, spaces, option_table[i].usage_text, screen_width);
+ indent_level -= 5;
+ fprintf (out, "\n");
+ }
+ }
+
+ indent_level -= 5;
+
+ fprintf (out, "\n%s('%s <filename>' also works, to specify the file to be debugged.)\n\n",
+ spaces_string.substr(0, indent_level).c_str(), name);
+}
+
+void
+BuildGetOptTable (lldb::OptionDefinition *expanded_option_table, struct option **getopt_table, int num_options)
+{
+ if (num_options == 0)
+ return;
+
+ uint32_t i;
+ uint32_t j;
+ std::bitset<256> option_seen;
+
+ 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;
+
+}
+
+SBError
+ParseOptions (Driver::OptionData &data, int argc, const char **argv)
+{
+ SBError error;
+ std::string option_string;
+ struct option *long_options = NULL;
+ int num_options;
+
+ for (num_options = 0; g_options[num_options].long_option != NULL; ++num_options);
+
+ if (num_options == 0)
+ {
+ if (argc > 1)
+ error.SetErrorStringWithFormat ("invalid number of options");
+ return error;
+ }
+
+ long_options = (struct option *) malloc ((num_options + 1) * sizeof (struct option));
+
+ BuildGetOptTable (g_options, &long_options, num_options);
+
+ if (long_options == NULL)
+ {
+ error.SetErrorStringWithFormat ("invalid long options");
+ return error;
+ }
+
+ // Build the option_string argument for call to getopt_long.
+
+ 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;
+ }
+ }
+ }
+
+ // Prepare for & make calls to getopt_long.
+
+ optreset = 1;
+ optind = 1;
+ int val;
+ while (1)
+ {
+ int long_options_index = -1;
+ val = ::getopt_long (argc, (char * const *) argv, option_string.c_str(), long_options, &long_options_index);
+
+ if (val == -1)
+ break;
+ else if (val == '?')
+ {
+ data.m_print_help = true;
+ error.SetErrorStringWithFormat ("unknown or ambiguous option");
+ break;
+ }
+ else if (val == 0)
+ continue;
+ else
+ {
+ 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)
+ {
+ error = Driver::SetOptionValue (long_options_index,
+ long_options[long_options_index].has_arg == no_argument ? NULL : optarg,
+ data);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("invalid option with value %i", val);
+ }
+ if (error.Fail())
+ break;
+ }
+ }
+
+ return error;
+}
+
+Driver::OptionData::OptionData () :
+ m_filename(),
+ m_script_lang (lldb::eScriptLanguageDefault),
+ m_source_command_files (),
+ m_debug_mode (false),
+ m_print_help (false),
+ m_print_version (false)
+
+{
+}
+
+Driver::OptionData::~OptionData ()
+{
+}
+
+void
+Driver::OptionData::Clear ()
+{
+ m_filename.clear ();
+ m_script_lang = lldb::eScriptLanguageDefault;
+ m_source_command_files.clear ();
+ m_debug_mode = false;
+ m_print_help = false;
+ m_print_version = false;
+}
+
+SBError
+Driver::SetOptionValue (int option_idx, const char *option_arg, Driver::OptionData &option_data)
+{
+ SBError error;
+ const char short_option = (char) g_options[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 'h':
+ option_data.m_print_help = true;
+ break;
+
+ case 'v':
+ option_data.m_print_version = true;
+ break;
+
+ case 'c':
+ option_data.m_crash_log = option_arg;
+ break;
+
+ case 'f':
+ {
+ SBFileSpec file(option_arg);
+ if (file.Exists())
+ option_data.m_filename = option_arg;
+ else
+ error.SetErrorStringWithFormat("file specified in --file (-f) option doesn't exist: '%s'", option_arg);
+ }
+ break;
+
+ case 'a':
+ if (!SBDebugger::SetDefaultArchitecture (option_arg))
+ error.SetErrorStringWithFormat("invalid architecture in the -a or --arch option: '%s'", option_arg);
+ break;
+
+ case 'l':
+ option_data.m_script_lang = SBDebugger::GetScriptingLanguage (option_arg);
+ break;
+
+ case 'd':
+ option_data.m_debug_mode = true;
+ break;
+
+ case 's':
+ {
+ SBFileSpec file(option_arg);
+ if (file.Exists())
+ option_data.m_source_command_files.push_back (option_arg);
+ else
+ error.SetErrorStringWithFormat("file specified in --source (-s) option doesn't exist: '%s'", option_arg);
+ }
+ break;
+
+ default:
+ option_data.m_print_help = true;
+ error.SetErrorStringWithFormat ("unrecognized option %c", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+Driver::ResetOptionValues ()
+{
+ m_option_data.Clear ();
+}
+
+const char *
+Driver::GetFilename() const
+{
+ if (m_option_data.m_filename.empty())
+ return NULL;
+ return m_option_data.m_filename.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.
+
+bool
+Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, FILE *err_fh)
+{
+ bool valid = true;
+
+ ResetOptionValues ();
+
+ if (argc == 2 && *(argv[1]) != '-')
+ {
+ m_option_data.m_filename = argv[1];
+ }
+ else
+ {
+ SBCommandReturnObject result;
+
+ SBError error = ParseOptions (m_option_data, argc, argv);
+ if (error.Fail())
+ {
+ const char *error_cstr = error.GetCString ();
+ if (error_cstr)
+ ::fprintf (err_fh, "error: %s\n", error_cstr);
+ }
+ }
+
+ // Check to see if they just invoked the debugger with a filename.
+
+
+ if (m_option_data.m_print_help)
+ {
+ ShowUsage (out_fh, g_options, m_option_data);
+ valid = false;
+ }
+ else if (m_option_data.m_print_version)
+ {
+ ::fprintf (out_fh, "%s\n", SBDebugger::GetVersionString());
+ valid = false;
+ }
+ else if (! m_option_data.m_crash_log.empty())
+ {
+ // Handle crash log stuff here.
+ }
+ else
+ {
+ // All other combinations are valid; do nothing more here.
+ }
+
+ return valid;
+}
+
+void
+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;
+ while ((len = SBDebugger::GetCurrentTarget().GetProcess().GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
+ m_io_channel_ap->OutWrite (stdio_buffer, len);
+}
+
+void
+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;
+ while ((len = SBDebugger::GetCurrentTarget().GetProcess().GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
+ m_io_channel_ap->ErrWrite (stdio_buffer, len);
+}
+
+void
+Driver::UpdateCurrentThread ()
+{
+ using namespace lldb;
+ SBProcess process(SBDebugger::GetCurrentTarget().GetProcess());
+ if (process.IsValid())
+ {
+ SBThread curr_thread (process.GetCurrentThread());
+ 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)
+ {
+ default:
+ case eStopReasonInvalid:
+ case eStopReasonNone:
+ break;
+
+ case eStopReasonTrace:
+ case eStopReasonBreakpoint:
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ if (!other_thread.IsValid())
+ other_thread = thread;
+ break;
+ case eStopReasonPlanComplete:
+ if (!plan_thread.IsValid())
+ plan_thread = thread;
+ break;
+ }
+ }
+ if (plan_thread.IsValid())
+ process.SetCurrentThread (plan_thread);
+ else if (other_thread.IsValid())
+ process.SetCurrentThread (other_thread);
+ else
+ {
+ if (curr_thread.IsValid())
+ thread = curr_thread;
+ else
+ thread = process.GetThreadAtIndex(0);
+
+ if (thread.IsValid())
+ process.SetCurrentThread (thread);
+ }
+ }
+ }
+}
+
+
+// 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 eStateAttaching:
+ case eStateLaunching:
+ case eStateStepping:
+ case eStateDetached:
+ {
+ char message[1024];
+ int message_len = ::snprintf (message, sizeof(message), "Process %d %s\n", process.GetProcessID(),
+ SBDebugger::StateAsCString (event_state));
+ m_io_channel_ap->OutWrite(message, message_len);
+ }
+ break;
+
+ case eStateRunning:
+ // Don't be chatty when we run...
+ break;
+
+ case eStateExited:
+ SBDebugger::HandleCommand("status");
+ m_io_channel_ap->RefreshPrompt();
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ // Make sure the program hasn't been auto-restarted:
+ if (SBProcess::GetRestartedFromEvent (event))
+ {
+ // FIXME: Do we want to report this, or would that just be annoyingly chatty?
+ char message[1024];
+ int message_len = ::snprintf (message, sizeof(message), "Process %d stopped and was programmatically restarted.\n",
+ process.GetProcessID());
+ m_io_channel_ap->OutWrite(message, message_len);
+ }
+ else
+ {
+ UpdateCurrentThread ();
+ SBDebugger::HandleCommand("status");
+ m_io_channel_ap->RefreshPrompt();
+ }
+ break;
+ }
+ }
+}
+
+// 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;
+ if (SBDebugger::GetCommandInterpreter().HandleCommand (command_string, result, true) != lldb::eReturnStatusQuit)
+ {
+ m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize());
+ m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize());
+ }
+ // 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;
+}
+
+
+//struct CrashImageInfo
+//{
+// std::string path;
+// VMRange text_range;
+// UUID uuid;
+//};
+//
+//void
+//Driver::ParseCrashLog (const char *crash_log)
+//{
+// printf("Parsing crash log: %s\n", crash_log);
+//
+// char image_path[PATH_MAX];
+// std::vector<CrashImageInfo> crash_infos;
+// if (crash_log && crash_log[0])
+// {
+// FileSpec crash_log_file (crash_log);
+// STLStringArray crash_log_lines;
+// if (crash_log_file.ReadFileLines (crash_log_lines))
+// {
+// const size_t num_crash_log_lines = crash_log_lines.size();
+// size_t i;
+// for (i=0; i<num_crash_log_lines; ++i)
+// {
+// const char *line = crash_log_lines[i].c_str();
+// if (strstr (line, "Code Type:"))
+// {
+// char arch_string[256];
+// if (sscanf(line, "%s", arch_string))
+// {
+// if (strcmp(arch_string, "X86-64"))
+// lldb::GetDefaultArchitecture ().SetArch ("x86_64");
+// else if (strcmp(arch_string, "X86"))
+// lldb::GetDefaultArchitecture ().SetArch ("i386");
+// else
+// {
+// ArchSpec arch(arch_string);
+// if (arch.IsValid ())
+// lldb::GetDefaultArchitecture () = arch;
+// else
+// fprintf(stderr, "Unrecognized architecture: %s\n", arch_string);
+// }
+// }
+// }
+// else
+// if (strstr(line, "Path:"))
+// {
+// const char *p = line + strlen("Path:");
+// while (isspace(*p))
+// ++p;
+//
+// m_option_data.m_filename.assign (p);
+// }
+// else
+// if (strstr(line, "Binary Images:"))
+// {
+// while (++i < num_crash_log_lines)
+// {
+// if (crash_log_lines[i].empty())
+// break;
+//
+// line = crash_log_lines[i].c_str();
+// uint64_t text_start_addr;
+// uint64_t text_end_addr;
+// char uuid_cstr[64];
+// int bytes_consumed_before_uuid = 0;
+// int bytes_consumed_after_uuid = 0;
+//
+// int items_parsed = ::sscanf (line,
+// "%llx - %llx %*s %*s %*s %n%s %n",
+// &text_start_addr,
+// &text_end_addr,
+// &bytes_consumed_before_uuid,
+// uuid_cstr,
+// &bytes_consumed_after_uuid);
+//
+// if (items_parsed == 3)
+// {
+//
+// CrashImageInfo info;
+// info.text_range.SetBaseAddress(text_start_addr);
+// info.text_range.SetEndAddress(text_end_addr);
+//
+// if (uuid_cstr[0] == '<')
+// {
+// if (info.uuid.SetfromCString (&uuid_cstr[1]) == 0)
+// info.uuid.Clear();
+//
+// ::strncpy (image_path, line + bytes_consumed_after_uuid, sizeof(image_path));
+// }
+// else
+// {
+// ::strncpy (image_path, line + bytes_consumed_before_uuid, sizeof(image_path));
+// }
+//
+// info.path = image_path;
+//
+// crash_infos.push_back (info);
+//
+// info.uuid.GetAsCString(uuid_cstr, sizeof(uuid_cstr));
+//
+// printf("0x%16.16llx - 0x%16.16llx <%s> %s\n",
+// text_start_addr,
+// text_end_addr,
+// uuid_cstr,
+// image_path);
+// }
+// }
+// }
+// }
+// }
+//
+// if (crash_infos.size())
+// {
+// SBTarget target (SBDebugger::CreateTarget (crash_infos.front().path.c_str(),
+// lldb::GetDefaultArchitecture().AsCString (),
+// false));
+// if (target.IsValid())
+// {
+//
+// }
+// }
+// }
+//}
+//
+
+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 = SBDebugger::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:
+ driver->ReadyForCommand();
+ break;
+
+ case eInputReaderDeactivate:
+ 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);
+ }
+ }
+
+
+ // struct termios stdin_termios;
+
+ if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0)
+ atexit (reset_stdin_termios);
+
+ ::setbuf (stdin, NULL);
+ ::setbuf (stdout, NULL);
+
+ SBDebugger::SetErrorFileHandle (stderr, false);
+ SBDebugger::SetOutputFileHandle (stdout, false);
+ SBDebugger::SetInputFileHandle (stdin, true);
+
+ // 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.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);
+ }
+
+// const char *crash_log = GetCrashLogFilename();
+// if (crash_log)
+// {
+// ParseCrashLog (crash_log);
+// }
+//
+ SBCommandInterpreter sb_interpreter = SBDebugger::GetCommandInterpreter();
+
+ m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, stdout, stderr, this));
+
+ struct winsize window_size;
+ if (isatty (STDIN_FILENO)
+ && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
+ {
+ char buffer[25];
+
+ sprintf (buffer, "set term-width %d", window_size.ws_col);
+ SBDebugger::HandleCommand ((const char *) buffer);
+ }
+
+ // 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 (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);
+ }
+
+ SBDebugger::PushInputReader (m_editline_reader);
+
+ SBListener listener(SBDebugger::GetListener());
+ if (listener.IsValid())
+ {
+
+ 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);
+
+ // 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 (SBDebugger::GetErrorFileHandle());
+ result.PutOutput (SBDebugger::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();
+ 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), "source '%s'", command_file);
+ SBDebugger::GetCommandInterpreter().HandleCommand (command_string, result, false);
+ if (GetDebugMode())
+ {
+ result.PutError (SBDebugger::GetErrorFileHandle());
+ result.PutOutput (SBDebugger::GetOutputFileHandle());
+ }
+ }
+ }
+
+ if (!m_option_data.m_filename.empty())
+ {
+ char arch_name[64];
+ if (SBDebugger::GetDefaultArchitecture (arch_name, sizeof (arch_name)))
+ ::snprintf (command_string, sizeof (command_string), "file --arch=%s '%s'", arch_name,
+ m_option_data.m_filename.c_str());
+ else
+ ::snprintf (command_string, sizeof(command_string), "file '%s'", m_option_data.m_filename.c_str());
+
+ SBDebugger::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(SBDebugger::GetErrorFileHandle());
+ result.PutOutput(SBDebugger::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);
+
+ ReadyForCommand ();
+
+ bool done = false;
+ while (!done)
+ {
+ 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))
+ {
+ done = true;
+ if (event_type & IOChannel::eBroadcastBitThreadDidExit)
+ iochannel_thread_exited = true;
+ break;
+ }
+ else
+ done = HandleIOEvent (event);
+ }
+ else if (event.BroadcasterMatchesRef (SBDebugger::GetCurrentTarget().GetProcess().GetBroadcaster()))
+ {
+ HandleProcessEvent (event);
+ }
+ else if (event.BroadcasterMatchesRef (sb_interpreter.GetBroadcaster()))
+ {
+ if (event_type & SBCommandInterpreter::eBroadcastBitQuitCommandReceived)
+ done = true;
+ }
+ }
+ }
+ }
+
+ reset_stdin_termios ();
+
+ CloseIOChannelFile ();
+
+ if (!iochannel_thread_exited)
+ {
+ SBEvent event;
+ 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();
+ }
+ }
+
+ SBProcess process = SBDebugger::GetCurrentTarget().GetProcess();
+ if (process.IsValid())
+ process.Destroy();
+ }
+ }
+}
+
+
+void
+Driver::ReadyForCommand ()
+{
+ if (m_waiting_for_command == false)
+ {
+ m_waiting_for_command = true;
+ BroadcastEventByType (Driver::eBroadcastBitReadyForInput, true);
+ }
+}
+
+
+int
+main (int argc, char const *argv[])
+{
+
+ SBDebugger::Initialize();
+
+ SBHostOS::ThreadCreated ("[main]");
+
+ // Do a little setup on the debugger before we get going
+ SBDebugger::SetAsync(true);
+ Driver driver;
+
+ bool valid_args = driver.ParseArgs (argc, argv, stdout, stderr);
+ if (valid_args)
+ {
+ driver.MainLoop ();
+ }
+
+ SBDebugger::Terminate();
+ return 0;
+}
diff --git a/lldb/tools/driver/Driver.h b/lldb/tools/driver/Driver.h
new file mode 100644
index 00000000000..ad82c989f1a
--- /dev/null
+++ b/lldb/tools/driver/Driver.h
@@ -0,0 +1,156 @@
+//===-- 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 "PseudoTerminal.h"
+
+#include <set>
+#include <bitset>
+#include <string>
+#include <vector>
+
+#include <LLDB/SBDefines.h>
+#include <LLDB/SBBroadcaster.h>
+#include <LLDB/SBError.h>
+#include <LLDB/SBInputReader.h>
+
+
+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);
+
+ bool
+ ParseArgs (int argc, const char *argv[], FILE *out_fh, FILE *err_fh);
+
+ 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 lldb::OptionDefinition m_cmd_option_table[];
+
+ std::string m_filename;
+ lldb::ScriptLanguage m_script_lang;
+ std::string m_crash_log;
+ std::vector<std::string> m_source_command_files;
+ bool m_debug_mode;
+ bool m_print_version;
+ bool m_print_help;
+ typedef std::set<char> OptionSet;
+ OptionSet m_seen_options;
+ };
+
+
+ static lldb::SBError
+ SetOptionValue (int option_idx,
+ const char *option_arg,
+ Driver::OptionData &data);
+
+
+private:
+ lldb_utility::PseudoTerminal m_editline_pty;
+ FILE *m_editline_slave_fh;
+ lldb::SBInputReader m_editline_reader;
+ std::auto_ptr<IOChannel> m_io_channel_ap;
+ OptionData m_option_data;
+ bool m_waiting_for_command;
+
+ void
+ ResetOptionValues ();
+
+ void
+ GetProcessSTDOUT ();
+
+ void
+ GetProcessSTDERR ();
+
+ void
+ UpdateCurrentThread ();
+
+ 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/lldb/tools/driver/IOChannel.cpp b/lldb/tools/driver/IOChannel.cpp
new file mode 100644
index 00000000000..a83e1b686e6
--- /dev/null
+++ b/lldb/tools/driver/IOChannel.cpp
@@ -0,0 +1,449 @@
+//===-- 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/SBCommandInterpreter.h>
+#include <LLDB/SBDebugger.h>
+#include <LLDB/SBError.h>
+#include <LLDB/SBEvent.h>
+#include <LLDB/SBFileSpec.h>
+#include <LLDB/SBHostOS.h>
+#include <LLDB/SBListener.h>
+#include <LLDB/SBStringList.h>
+
+using namespace lldb;
+
+typedef std::map<EditLine *, std::string> PromptMap;
+const char *g_default_prompt = "(lldb) ";
+PromptMap g_prompt_map;
+
+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();
+}
+
+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;
+ }
+}
+
+unsigned char
+IOChannel::HandleCompletion (EditLine *e, int ch)
+{
+ assert (e == m_edit_line);
+
+ const LineInfo *line_info = el_line(m_edit_line);
+ SBStringList completions;
+ size_t page_size = 40;
+
+ int num_completions
+ = SBDebugger::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;
+ }
+
+ // 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));
+ if (num_completions < page_size)
+ {
+ for (int i = 1; i < num_elements; i++)
+ {
+ const char *completion_str = completions.GetStringAtIndex(i);
+ OutWrite("\n\t", 2);
+ OutWrite(completion_str, strlen (completion_str));
+ }
+ OutWrite ("\n", 1);
+ }
+ 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++)
+ {
+ const char *completion_str = completions.GetStringAtIndex(cur_pos);
+ OutWrite("\n\t", 2);
+ OutWrite(completion_str, strlen (completion_str));
+ }
+
+ if (cur_pos >= num_elements)
+ {
+ OutWrite("\n", 1);
+ break;
+ }
+
+ OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "));
+ 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 *in,
+ FILE *out,
+ FILE *err,
+ Driver *driver
+) :
+ SBBroadcaster ("IOChannel"),
+ 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_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFileName(), in, out, err)),
+ m_history (history_init()),
+ m_completion_key ("\t")
+{
+ 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);
+
+ // Source $PWD/.editrc then $HOME/.editrc
+ ::el_source (m_edit_line, NULL);
+
+ 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_CLIENTDATA, this);
+
+ 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);
+}
+
+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;
+ }
+}
+
+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 (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);
+ }
+ }
+}
+
+bool
+IOChannel::LibeditGetInput (std::string &new_line)
+{
+ if (m_edit_line != NULL)
+ {
+ int line_len = 0;
+ const char *line = ::el_gets (m_edit_line, &line_len);
+ if (line)
+ {
+ // 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
+ {
+ // Someone just hit ENTER, return the empty string
+ new_line.clear();
+ }
+ // Return true to indicate success even if a string is empty
+ return true;
+ }
+ }
+ // Return false to indicate failure. This can happen when the file handle
+ // is closed (EOF).
+ new_line.clear();
+ return false;
+}
+
+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 (SBDebugger::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())
+ {
+ if (LibeditGetInput(line) == false)
+ {
+ // EOF or some other file error occurred
+ 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;
+ break;
+ }
+ }
+ 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;
+ break;
+ }
+ }
+ }
+ }
+ BroadcastEventByType (IOChannel::eBroadcastBitThreadDidExit);
+ m_driver = NULL;
+ m_read_thread = NULL;
+}
+
+bool
+IOChannel::Start ()
+{
+ if (m_read_thread != LLDB_INVALID_HOST_THREAD)
+ return true;
+
+ m_read_thread = SBHostOS::ThreadCreate ("<lldb.driver.commandline_io>", IOChannel::IOReadThread, this,
+ NULL);
+
+ return (m_read_thread != LLDB_INVALID_HOST_THREAD);
+}
+
+bool
+IOChannel::Stop ()
+{
+ if (m_read_thread == NULL)
+ 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 ()
+{
+ ::el_set (m_edit_line, EL_REFRESH);
+}
+
+void
+IOChannel::OutWrite (const char *buffer, size_t len)
+{
+ if (len == 0)
+ return;
+ ::fwrite (buffer, 1, len, m_out_file);
+}
+
+void
+IOChannel::ErrWrite (const char *buffer, size_t len)
+{
+ if (len == 0)
+ return;
+ ::fwrite (buffer, 1, len, m_err_file);
+}
+
+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();
+}
diff --git a/lldb/tools/driver/IOChannel.h b/lldb/tools/driver/IOChannel.h
new file mode 100644
index 00000000000..dec7c82da29
--- /dev/null
+++ b/lldb/tools/driver/IOChannel.h
@@ -0,0 +1,113 @@
+//===-- 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>
+
+#include <editline/readline.h>
+#include <histedit.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
+ };
+
+ IOChannel (FILE *in,
+ 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);
+
+ void
+ ErrWrite (const char *buffer, size_t len);
+
+ bool
+ LibeditGetInput (std::string &);
+
+ 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 ();
+
+ static unsigned char ElCompletionFn (EditLine *e, int ch);
+
+ bool
+ IsGettingCommand () const;
+
+private:
+
+ 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;
+ void
+ HistorySaveLoad (bool save);
+ unsigned char HandleCompletion (EditLine *e, int ch);
+};
+
+#endif // lldb_IOChannel_h_
diff --git a/lldb/tools/driver/lldb-Info.plist b/lldb/tools/driver/lldb-Info.plist
new file mode 100644
index 00000000000..7c1bfc734a7
--- /dev/null
+++ b/lldb/tools/driver/lldb-Info.plist
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.lldb</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>lldb</string>
+ <key>CFBundleVersion</key>
+ <string>2</string>
+ <key>SecTaskAccess</key>
+ <array>
+ <string>allowed</string>
+ <string>debug</string>
+ </array>
+</dict>
+</plist>
diff --git a/lldb/www/content.css b/lldb/www/content.css
new file mode 100644
index 00000000000..ab6983b4849
--- /dev/null
+++ b/lldb/www/content.css
@@ -0,0 +1,25 @@
+html, body {
+ padding:0px;
+ font-size:small; font-family:"Lucida Grande", "Lucida Sans Unicode", Arial, Verdana, Helvetica, sans-serif; background-color: #fff; color: #222;
+ line-height:1.5;
+}
+
+h1, h2, h3, tt { color: #000 }
+
+h1 { padding-top:0px; margin-top:0px;}
+h2 { color:#333333; padding-top:0.5em; }
+h3 { padding-top: 0.5em; margin-bottom: -0.25em; color:#2d58b7}
+li { padding-bottom: 0.5em; }
+ul { padding-left:1.5em; }
+
+/* Slides */
+IMG.img_slide {
+ display: block;
+ margin-left: auto;
+ margin-right: auto
+}
+
+.itemTitle { color:#2d58b7 }
+
+/* Tables */
+tr { vertical-align:top }
diff --git a/lldb/www/index.html b/lldb/www/index.html
new file mode 100644
index 00000000000..00bebe1780c
--- /dev/null
+++ b/lldb/www/index.html
@@ -0,0 +1,197 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>The LLDB Debugger</title>
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
+</head>
+
+<body>
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+ <!--*********************************************************************-->
+ <h1>The LLDB Debugger</h1>
+ <!--*********************************************************************-->
+
+ <p>LLDB is a next generation, high-performance debugger. It is built as a set
+ of reusable components which highly leverage existing libraries in the
+ larger LLVM Project, such as the Clang expression parser and LLVM
+ disassembler.</p>
+ <p>LLDB is in early development, but is mature enough to support basic
+ debugging scenarios on Mac OS X in C, Objective-C and C++.</p>
+
+ <p>All of the code in the LLDB project is available under the standard
+ <a href="http://llvm.org/docs/DeveloperPolicy.html#license">LLVM
+ License</a>, an open source "BSD-style" license.</p>
+
+ <!--=====================================================================-->
+ <h2 id="goals">Goals</h2>
+ <!--=====================================================================-->
+
+ <p>The current state of the art in open source debuggers are that
+ they work in the common cases for C applications, but don't
+ handle many "hard cases" properly. For example, C++ expression
+ parsing, handling overloading, templates, multi-threading, and
+ other non-trivial scenarios all work in some base cases, but
+ don't work reliably.</p>
+
+ <p>The goal of LLDB is to provide an amazing debugging experience that "just
+ works". We aim to solve these long-standing problems where debuggers get
+ confused, so that you can think about debugging your problem, not
+ about deficiencies in the debugger.</p>
+
+ <p>With a long view, there is no good reason for a debugger to
+ reinvent its own C/C++ parser, type system, know all the
+ target calling convention details, implement its own disassembler,
+ etc. By using the existing libraries vended by the LLVM
+ project, we believe that many of these problems will be defined
+ away, and the debugger can focus on important issues like
+ process control, efficient symbol reading and indexing, thread
+ management, and other debugger-specific problems.</p>
+
+ <p>Some more specific goals include:</p>
+
+ <ul>
+ <li>Build libraries for inclusion in IDEs, command line tools, and
+ other analysis tools</li>
+ <li>High performance and efficient memory use</li>
+ <li>Extensible: Python scriptable and use a plug-in architecture</li>
+ <li>Reuse existing compiler technology where it makes sense</li>
+ <li>Excellent multi-threaded debugging support</li>
+ <li>Great support for C, Objective-C and C++</li>
+ <li>Retargetable to support multiple platforms</li>
+ <li>Provide a base for debugger research and other innovation</li>
+ </ul>
+
+ <!--=====================================================================-->
+ <h2 id="why">Why a new debugger?</h2>
+ <!--=====================================================================-->
+
+ <p>In order to achieve our goals we decided to start with a fresh architecture
+ that would support modern multi-threaded programs, handle debugging symbols
+ in an efficient manner, use compiler based code knowledge and have plug-in
+ support for functionality and extensions. Additionally we want the debugger
+ capabilities to be available to other analysis tools, be they scripts or
+ compiled programs, without requiring them to be GPL.</p>
+
+ <!--=====================================================================-->
+ <h2 id="features">Features</h2>
+ <!--=====================================================================-->
+
+ <p>LLDB supports a broad variety of basic debugging features such as
+ reading DWARF, supporting step, next, finish, backtraces, etc. Some
+ more interested bits are:</p>
+
+ <ul>
+ <li>Plug-in architecture for portability and extensibility:
+ <ul>
+ <li>Object file parsers for executable file formats. Support currently
+ includes Mach-O (32 and 64-bit) &amp; ELF (32-bit).</li>
+ <li>Object container parsers to extract object files contained within a file.
+ Support currently includes universal Mach-O files &amp; BSD Archives.
+ </li>
+ <li>Debug symbol file parsers to incrementally extract debug information from
+ object files. Support currently includes DWARF &amp; Mach-O symbol
+ tables.</li>
+ <li>Symbol vendor plug-ins collect data from a variety of different sources
+ for an executable object.</li>
+ <li>Disassembly plug-ins for each architecture. Support currently includes
+ an LLVM disassembler for <a
+ href="http://blog.llvm.org/2010/01/x86-disassembler.html">i386,
+ x86_64</a>, &amp; ARM/Thumb.</li>
+ <li>Debugger plug-ins implement the host and target specific functions
+ required to debug.</li>
+ </ul>
+ <li>SWIG-generated script bridging allows Python to access and control the
+ public API of the debugger library.</li>
+ <li>A remote protocol server, debugserver, implements Mac OS X debugging on
+ i386 and x86_64.</li>
+ <li>A command line debugger - the lldb executable itself.</li>
+ <li>A framework API to the library.</li>
+ </ul>
+
+ <!--=====================================================================-->
+ <h2 id="requirements">Platform Support</h2>
+ <!--=====================================================================-->
+
+ <p>LLDB is known to work on the following platforms, but ports to new
+ platforms are welcome:</p>
+
+ <li>Machine Architectures:
+ <ul>
+ <li>Mac OS X i386 and X86-64</li>
+ </ul></li>
+
+ <!--=====================================================================-->
+ <h2 id="status">Current Status</h2>
+ <!--=====================================================================-->
+
+ <p>LLDB is in early development and supports basic debugging scenarios on
+ Mac OS X. The public API has not been finalized, and different parts are
+ at different levels of maturity. We welcome any help fleshing out missing
+ pieces and improving the code.</p>
+
+ <p>What works well:</p>
+ <ul>
+ <li>Process control, including external process control via debugserver
+ (which is included as part of the lldb project)</li>
+ <li>Breakpoints: Source-line, symbolic, C++ mangled names, module
+ scoping</li>
+ <li>Symbol reading and object file introspection</li>
+ <li>Script bridging</li>
+ <li>Thread inspection and stepping</li>
+ <li>Disassembly of i386, x86_64, &amp; ARM/Thumb machine code, and
+ backtracing on i386 &amp; x86_64</li>
+ <li>The basic command line prompt system, shared library tracking,
+ source listings.</li>
+ </ul>
+
+ <p>What is still pretty new:</p>
+ <ul>
+ <li>The public API to the library</li>
+ <li>Expression evaluation</li>
+ <li>Objective-C support: stepping into/over, printing the description of
+ an object ("po")</li>
+ <li>Breakpoint actions &amp; scripts</li>
+ <li>Attaching to existing processes</li>
+ </ul>
+
+ <p>What isn't there yet:</p>
+ <ul>
+ <li>Regression test suite</li>
+ <li>Operating system support hasn't been fully modularized yet</li>
+ <li><a href="http://clang.llvm.org/docs/LanguageExtensions.html#blocks">Blocks</a> support</li>
+ <li>Calling functions in expressions</li>
+ <li>Objective-C 2.0 Support: Printing properties, synthetic properties,
+ Objective-C expressions, KVO, dynamic types, dot syntax, runtime data</li>
+ <li>C++ support: Method access, handling demangled names, dynamic types</li>
+ <li>Exception support: Breaking by name, thrown object, thrower</li>
+</li>
+ </ul>
+
+ <!--=====================================================================-->
+ <h2>Get it and get involved!</h2>
+ <!--=====================================================================-->
+
+ <p>To check out the code, use:</p>
+
+ <ul>
+ <li>svn co http://llvm.org/svn/llvm-project/lldb/trunk lldb</li>
+ </ul>
+
+ <p>Note that LLDB currently only builds out of the box on Darwin with
+ Xcode, but patches to improve portability are definitely welcome.</p>
+
+ <p>Discussions about LLDB should go to the <a
+ href="http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev">lldb-dev</a> mailing
+ list. Commit messages for the lldb SVN module are automatically sent to the
+ <a
+ href="http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits">lldb-commits</a>
+ mailing list, and this is also the preferred mailing list for patch
+ submissions.</p>
+</div>
+</body>
+</html>
diff --git a/lldb/www/menu.css b/lldb/www/menu.css
new file mode 100644
index 00000000000..6e96a457ab5
--- /dev/null
+++ b/lldb/www/menu.css
@@ -0,0 +1,39 @@
+/***************/
+/* page layout */
+/***************/
+
+[id=menu] {
+ position:fixed;
+ width:25ex;
+}
+[id=content] {
+ /* ***** EDIT THIS VALUE IF CONTENT OVERLAPS MENU ***** */
+ position:absolute;
+ left:29ex;
+ padding-right:4ex;
+}
+
+/**************/
+/* menu style */
+/**************/
+
+#menu .submenu {
+ padding-top:1em;
+ display:block;
+}
+
+#menu label {
+ display:block;
+ font-weight: bold;
+ text-align: center;
+ background-color: rgb(192,192,192);
+}
+#menu a {
+ padding:0 .2em;
+ display:block;
+ text-align: center;
+ background-color: rgb(235,235,235);
+}
+#menu a:visited {
+ color:rgb(100,50,100);
+} \ No newline at end of file
diff --git a/lldb/www/menu.html.incl b/lldb/www/menu.html.incl
new file mode 100644
index 00000000000..ed104c0c30a
--- /dev/null
+++ b/lldb/www/menu.html.incl
@@ -0,0 +1,20 @@
+<div id="menu">
+ <div>
+ <a href="http://llvm.org/">LLVM Home</a>
+ </div>
+
+ <div class="submenu">
+ <label>LLDB Info</label>
+ <a href="/index.html">About</a>
+ </div>
+
+ <div class="submenu">
+ <label>Quick Links</label>
+ <a href="http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev">lldb-dev</a>
+ <a href="http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits">lldb-commits</a>
+ <a href="http://llvm.org/bugs/">Bug Reports</a>
+ <a href="http://llvm.org/svn/llvm-project/lldb/trunk/">Browse SVN</a>
+ <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/">Browse ViewVC</a>
+ </div>
+</div>
+
OpenPOWER on IntegriCloud